diff --git a/.travis.yml b/.travis.yml index 021aa63ec..9071e3867 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,9 @@ language: ruby rvm: - 1.9.3 -script: rake ci:check +script: rake ci:parallel_check notifications: - email: false \ No newline at end of file + email: + recipients: + - jn.avila@free.fr + diff --git a/Gemfile b/Gemfile index 79f6c3029..59fd845ae 100644 --- a/Gemfile +++ b/Gemfile @@ -1,5 +1,5 @@ source 'https://rubygems.org' -gem 'maruku', '0.6.1' +gem 'maruku', '0.7.1' gem 'redcarpet' -gem 'rdiscount' +gem 'parallel' diff --git a/README.md b/README.md index 5e72d6d1f..39d3f6dfa 100644 --- a/README.md +++ b/README.md @@ -1,58 +1,9 @@ -[![Build Status](https://secure.travis-ci.org/progit/progit.png?branch=master)](https://travis-ci.org/progit/progit) +# Pro Git, 1st Edition -# Pro Git Book Contents +This is the source for the 1st edition of the Pro Git book. The second edition has since been released and is what will be maintained and published going forward. Please suggest any changes to that version instead. -This is the source code for the Pro Git book contents. It is licensed under -the Creative Commons Attribution-Non Commercial-Share Alike 3.0 license. I -hope you enjoy it, I hope it helps you learn Git, and I hope you'll support -Apress and me by purchasing a print copy of the book at Amazon: +You can find the new edition at: -http://tinyurl.com/amazonprogit +https://github.com/progit/progit2 -It is also available online at: - -http://git-scm.com/book/ - -and fully translated in 10 languages. - -# Making Ebooks - -On Fedora (16 and later) you can run something like this:: - - $ yum install ruby calibre rubygems ruby-devel rubygem-ruby-debug rubygem-rdiscount - $ makeebooks en # will produce a mobi - -On MacOS you can do like this:: - -1. INSTALL ruby and rubygems -2. `$ gem install rdiscount` -3. DOWNLOAD Calibre for MacOS and install command line tools. You'll need some dependencies to generate a PDF: - * pandoc: http://johnmacfarlane.net/pandoc/installing.html - * xelatex: http://tug.org/mactex/ -4. `$ makeebooks zh` #will produce a mobi - -## Notes on pandoc - -Please use Pandoc version 1.11.1 or later as older versions(confirmed on 1.9.1.1) has a [bug](https://github.com/jgm/pandoc/issues/964) which hides a word after tilde `~`. You can do `pandoc -v` to see which version you have installed. - -# Errata - -If you see anything that is technically wrong or otherwise in need of -correction, please [open an issue](https://github.com/progit/progit/issues/new) and one of the maintainers will take a look. - - -# Translation - -If you wish to translate the book, your work will be put up on the -git-scm.com site. Please put your translation into the appropriate -subdirectory of this project, using the -[ISO 639](http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) -and send a pull request. - -# Sending a pull request - -* Be careful to use UTF-8 encoding in your files. -* Do not mix changes to the original english with translations in a single pull request. -* If your pull request changes a translation, prefix your pull request and commits'messages with the ISO 639 code, e.g. `[de] Update chapter 2`. Please only push files where there is already some translation done. -* Make sure the translation changes can be automatically merged. The maintainers can not make the merge manually if there are some conflicts. -* Make as sure as possible that the changes work correctly for publishing to pdf, ebooks and the git-scm.com website +If you're looking for the original README content, it can be found in the [README.original.md](README.original.md) file. diff --git a/README.original.md b/README.original.md new file mode 100644 index 000000000..b6556fd75 --- /dev/null +++ b/README.original.md @@ -0,0 +1,70 @@ +[![Build Status](https://secure.travis-ci.org/progit/progit.png?branch=master)](https://travis-ci.org/progit/progit) + +# Pro Git Book Contents + +This is the source code for the Pro Git book contents. It is licensed under +the Creative Commons Attribution-Non Commercial-Share Alike 3.0 license. I +hope you enjoy it, I hope it helps you learn Git, and I hope you'll support +Apress and me by purchasing a print copy of the book at Amazon: + +http://tinyurl.com/amazonprogit + +It is also available online at: + +http://git-scm.com/book/ + +and fully translated in 10 languages. + +# Making Ebooks + +On Fedora (16 and later) you can run something like this:: + + $ yum install ruby calibre rubygems ruby-devel rubygem-ruby-debug rubygem-rdiscount + $ makeebooks en # will produce a mobi + +On MacOS you can do like this: + +1. INSTALL ruby and rubygems +2. `$ gem install rdiscount` +3. DOWNLOAD Calibre for MacOS and install command line tools. You'll need some dependencies to generate a PDF: + * pandoc: http://johnmacfarlane.net/pandoc/installing.html + * xelatex: http://tug.org/mactex/ +4. `$ makeebooks zh` #will produce a mobi + +On Windows you can do like this: + +1. Install ruby and related tool from http://rubyinstaller.org/downloads/ + * RubyInstaller (ruby & gem) + * Development Kit (to build rdiscount gem) +2. Open `cmd` and `$ gem install rdiscount` +3. Install Calibre for Windows from http://calibre-ebook.com/download +4. `$ SET ebook_convert_path=c:\Program Files\Calibre2\ebook-convert.exe`. Modify to suit with your Calibre installed path. +5. Make ebooks: + * `$ ruby makeebooks vi` #will produce a mobi + * `$ SET FORMAT=epub` then `$ ruby makeebooks vi` #will produce an epub + +## Notes on pandoc + +Please use Pandoc version 1.11.1 or later as older versions (confirmed on 1.9.1.1) has a [bug](https://github.com/jgm/pandoc/issues/964) which hides a word after tilde `~`. You can do `pandoc -v` to see which version you have installed. + +# Errata + +If you see anything that is technically wrong or otherwise in need of +correction, please [open an issue](https://github.com/progit/progit/issues/new) and one of the maintainers will take a look. + + +# Translation + +If you wish to translate the book, your work will be put up on the +git-scm.com site. Please put your translation into the appropriate +subdirectory of this project, using the +[ISO 639](http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes) code +and send a pull request. + +# Sending a pull request + +* Be careful to use UTF-8 encoding in your files. +* Do not mix changes to the original English with translations in a single pull request. +* If your pull request changes a translation, prefix your pull request and commits' messages with the ISO 639 code, e.g. `[de] Update chapter 2`. Please only push files where there is already some translation done. +* Make sure the translation changes can be automatically merged. The maintainers can not make the merge manually if there are some conflicts. +* Make as sure as possible that the changes work correctly for publishing to PDF, ebooks and the git-scm.com website. diff --git a/Rakefile b/Rakefile index c9b0d9b3f..3aeaebf78 100644 --- a/Rakefile +++ b/Rakefile @@ -160,15 +160,100 @@ namespace :pdf do end class StderrDecorator + def initialize(out) + @out = out + end + def <<(x) - $stderr<< "#{x}" + @out << "#{x}" if x.match /REXML/ raise "" end end end +def test_lang(lang, out) + error_code = false + chapter_figure = { + "01-introduction" => 7, + "02-git-basics" => 2, + "03-git-branching" => 39, + "04-git-server" => 15, + "05-distributed-git" => 27, + "06-git-tools" => 1, + "07-customizing-git" => 3, + "08-git-and-other-scms" => 0, + "09-git-internals" => 4} + source_files = FileList.new(File.join(lang, '0*', '*.markdown')).sort + source_files.each do |mk_filename| + src_file = File.open(mk_filename, 'r') + figure_count = 0 + until src_file.eof? + line = src_file.readline + matches = line.match /^#/ + if matches + if line.match /^(#+).*#[[:blank:]]+$/ + out<< "\nBadly formatted title in #{mk_filename}: #{line}\n" + error_code = true + end + end + if line.match /^\s*Insert\s(.*)/i + if line.match /^\s*Insert\s(.*)/ + figure_count = figure_count + 1 + else + out << "\n#{lang}: Badly cased Insert directive: #{line}\n" + error_code = true + end + end + end + # This extraction is a bit contorted, because the pl translation renamed + # the files, so the match is done on the directories. + tab_fig_count = chapter_figure[File.basename(File.dirname(mk_filename))] + expected_figure_count = tab_fig_count ? tab_fig_count:0 + if figure_count > expected_figure_count + out << "\nToo many figures declared in #{mk_filename}\n" + error_code = true + end + end + begin + mark = (source_files.map{|mk_filename| File.open(mk_filename, 'r'){ + |mk| mk.read.encode("UTF-8")}}).join("\n\n") + require 'maruku' + code = Maruku.new(mark, :on_error => :raise, :error_stream => StderrDecorator.new(out)) + rescue + print $! + error_code = true + end + error_code +end + +$out = $stdout + namespace :ci do + desc "Parallel Continuous integration" + task :parallel_check do + require 'parallel' + langs = FileList.new('??')+FileList.new('??-??') + results = Parallel.map(langs) do |lang| + error_code = test_lang(lang, $out) + if error_code + print "processing #{lang} KO\n" + else + print "processing #{lang} OK\n" + end + error_code + end + fail "At least one language conversion failed" if results.any? + end + + (FileList.new('??')+FileList.new('??-??')).each do |lang| + desc "testing " + lang + task (lang+"_check").to_sym do + error_code = test_lang(lang, $out) + fail "processing #{lang} KO\n" if error_code + print "processing #{lang} OK\n" + end + end desc "Continuous Integration" task :check do @@ -184,59 +269,17 @@ namespace :ci do end langs -= excluded_langs end - error_code = false - chapter_figure = { - "01-introduction" => 7, - "02-git-basics" => 2, - "03-git-branching" => 39, - "04-git-server" => 15, - "05-distributed-git" => 27, - "06-git-tools" => 1, - "07-customizing-git" => 3, - "08-git-and-other-scms" => 0, - "09-git-internals" => 4} - langs.each do |lang| + errors = langs.map do |lang| print "processing #{lang} " - mark = '' - source_files = FileList.new(File.join(lang, '0*', '*.markdown')).sort - source_files.each do |mk_filename| - mk_file = File.open(mk_filename, 'r') do |mk| - mark+= mk.read.encode("UTF-8") - end - src_file = File.open(mk_filename, 'r') - figure_count = 0 - until src_file.eof? - line = src_file.readline - matches = line.match /^#/ - if matches - if line.match /^(#+).*#[[:blank:]]+$/ - print "\nBadly formatted title in #{mk_filename}: #{line}\n" - error_code = true - end - end - if line.match /^\s*Insert\s(.*)/ - figure_count = figure_count + 1 - end - end - # This extraction is a bit contorted, because the pl translation renamed - # the files, so the match is done on the directories. - tab_fig_count = chapter_figure[File.basename(File.dirname(mk_filename))] - expected_figure_count = tab_fig_count ? tab_fig_count:0 - if figure_count > expected_figure_count - print "\nToo many figures declared in #{mk_filename}\n" - error_code = true - end - end - begin - code = Maruku.new(mark, :on_error => :raise, :error_stream => StderrDecorator.new) - print "OK\n" - rescue + error_code=test_lang(lang, $out) + if error_code print "KO\n" - print $! - error_code = true + else + print "OK\n" end + error_code end - fail "At least one language conversion failed" if error_code + fail "At least one language conversion failed" if errors.any? end end diff --git a/ar/01-introduction/01-chapter1.markdown b/ar/01-introduction/01-chapter1.markdown index c91e325ea..6ec46b534 100644 --- a/ar/01-introduction/01-chapter1.markdown +++ b/ar/01-introduction/01-chapter1.markdown @@ -168,7 +168,7 @@ If a particular version of a file is in the git directory, it’s considered com هناك طريقتين للتنصيب على ماك أو اس، الأسهل هي استخدام الواجهة الرسومية للتنصيب، والتي يمكنك تحميلها من صفحة المشروع على غوغل كود (انظر الشكل 1-7): - http://code.google.com/p/git-osx-installer + http://sourceforge.net/projects/git-osx-installer/ Insert 18333fig0107.png الشكل 1-7. تنصيب Git على ماك أو اس. diff --git a/ar/02-git-basics/01-chapter2.markdown b/ar/02-git-basics/01-chapter2.markdown index 42771d7b9..72948c863 100644 --- a/ar/02-git-basics/01-chapter2.markdown +++ b/ar/02-git-basics/01-chapter2.markdown @@ -1,4 +1,4 @@ -# مبادئ Git # +# مبادئ Git # إذا كان هناك فصل واحد عليك قراءته لكي تبدأ بإستخدام Git، فعليك بهذا الفصل! يغطي هذا الفصل جميع الأوامر الأساسية التي عليك معرفتها لكي تتمكن من القيام بأغلب الأمور أثناء استخدامك لـ Git. في نهاية هذا الفصل يجب أن تكون قادراً على انشاء واعداد الـ repository لمشروعك وعلى تحديد الملفات التي ستتم متابعتها والتي ستترك، وعلى تهييئ التغييرات لعمل commit عليها. ستتعلم أيضاً كيف تعد Git لكي تتجاهل بعض أنواع الملفات، كيف تقوم بالتراجع عن الأخطاء التي سترتكبها بسرعة وبسهولة، كيف تتصفح تاريخ مشروعك وكيف تعرض التغيرات بين الـ commits، وكيف تنشر وتسحب (push & pull) التغيرات من الـ repositories البعيدة عنك. @@ -40,27 +40,26 @@ هناك عدد من البروتوكولات المختلفة التي يمكنك اسستعمالها لنقل المعلومات في git. المثال السابق يستعمل بروتوكول 'git://'، ولكن من الممكن أن تجد أيضاً استخداماً لـ 'http(s)://' أو 'user@server:/path.git'، والتي تستعمل بروتوكول SSH في النقل. في الفصل الرابع من الكتاب ستتعرف على الخيارات المتوفرة للتواصل مع الـ repository الخاصة بك وميزات ومساوئ كل منها. ## تسجيل التعديلات في الـ repository ## +لديك repository أصلي ونسخة لتعمل عليها من ملفات المشروع. عليك أن تقوم ببعض التعديلات ثم تعمل commit لهذه التعديلات في repository الخاص بك في كل مرة يصل فيها المشروع إلى نقطة تود تسجيلها. -You have a bona fide Git repository and a checkout or working copy of the files for that project. You need to make some changes and commit snapshots of those changes into your repository each time the project reaches a state you want to record. +تذكر أنه كل ملف في مجلد العمل يمكن أن يكون في إحدى الحالتين فقط: مٌتَتَبّع tracked أو غير مٌتَتَبّع untracked. الملفات المٌتتبّعة هي ملفات كانت في أخر snapshot ويمكن إلغاء التعديلات عليها أو التعديل عليها أو وضعه في حالة staged (جاهز من أجل commit). الملفات غير المُتتبّعة هي كل الملفات الآخرى - أي ملف في مجلد العمل لم يكن موجوداً في آخر snapshot وليس معلماً بأنه staged. عندما تقوم باستنساخ repository جميع ملفاتك تكون بحالة متتبّعة tracked و غير معدلة unmodified لأنك قمت للتو بعمل check out ولم تقم بأي تعديل. -Remember that each file in your working directory can be in one of two states: tracked or untracked. Tracked files are files that were in the last snapshot; they can be unmodified, modified, or staged. Untracked files are everything else - any files in your working directory that were not in your last snapshot and are not in your staging area. When you first clone a repository, all of your files will be tracked and unmodified because you just checked them out and haven’t edited anything. - -As you edit files, Git sees them as modified, because you’ve changed them since your last commit. You stage these modified files and then commit all your staged changes, and the cycle repeats. This lifecycle is illustrated in Figure 2-1. +عندما تعدل الملفات، سيقوم git بتأشيرهم على أنهم modified، لأنك قمت بتغيرهم عن آخر commit. تقوم بعمل stage لهذه الملفات المعدلة ثم تقوم بعمل commit لجميع التغيرات في منطقة stage، وتتكرر العملية. يوضع الشكل 2-1 دورة العملية. Insert 18333fig0201.png -Figure 2-1. The lifecycle of the status of your files. +الشكل 2-1. دورة حالة الملفات. -### Checking the Status of Your Files ### +### تفقد حالة ملفاتك ### -The main tool you use to determine which files are in which state is the git status command. If you run this command directly after a clone, you should see something like this: +باستخدام الأمر git status يمكننا معرفة حالة الملفات لدينا. إذا قمت بتشغيل هذا الأمر مباشرة بعد قيامك بعمل clone يجب أن ترى شيئاً يشبه التالي: $ git status # On branch master - nothing to commit (working directory clean) + nothing to commit, working directory clean -This means you have a clean working directory—in other words, there are no tracked and modified files. Git also doesn’t see any untracked files, or they would be listed here. Finally, the command tells you which branch you’re on. For now, that is always master, which is the default; you won’t worry about it here. The next chapter will go over branches and references in detail. +وهذا يعني أنه لديك مجلد عمل نظيف - بمعنى آخر، لايوجد أي ملفات معدلة أو ملفات غير مُتتبّعة. كما أنّ هذا الأمر يخبرك بأي فرع branch أنت تعمل. حالياً، دائماً هو master، وهو الافتراضي؛ في الفصل المقبل سنمر على الأفرع و المرجعيات references بالتفصيل. -Let’s say you add a new file to your project, a simple README file. If the file didn’t exist before, and you run `git status`, you see your untracked file like so: +لنقل بأنك قمت بإضافة ملف جديد على مشروعك، وليكن ملف README بسيط. إذا لم يكن الملف موجوداً مسبقاً، وقمت بتنفيذ الأمر `git status` سترى الملف غير مُتتبّعاً كما يلي: $ vim README $ git status @@ -71,15 +70,15 @@ Let’s say you add a new file to your project, a simple README file. If the fil # README nothing added to commit but untracked files present (use "git add" to track) -You can see that your new README file is untracked, because it’s under the “Untracked files” heading in your status output. Untracked basically means that Git sees a file you didn’t have in the previous snapshot (commit); Git won’t start including it in your commit snapshots until you explicitly tell it to do so. It does this so you don’t accidentally begin including generated binary files or other files that you did not mean to include. You do want to start including README, so let’s start tracking the file. +يمكنك ملاحظة أنّ ملفك الجديد README غير مُتتبّع، فهو تحت تبويب "untracked files" في خرج الأمر. ويعني ذلك أنّ git يرى ملفاً جديداً على commit السابقة؛ علماً أنّ git لن يقوم بإضافة هذا الملف إلى الملفات المتتبعة إلا إذا قمت بطلب ذلك بشكل مباشر، والهدف من ذلك من أجل حماية المشروع من الضم الخاطئ لملفات binary أو أي ملفات لا تود بإضافتها. إلاّ أنّك ترغب في إضافة README إلى الملفات المتتبّعة. وسنقوم بذلك حالاً. -### Tracking New Files ### +### تتبع الملفات الجديدة ### -In order to begin tracking a new file, you use the command `git add`. To begin tracking the README file, you can run this: +للقيام بتتبع ملف جديد عليه استخدام الأمر `git add` . مثلاً لنقم بتتبع الملف الجديد README: $ git add README -If you run your status command again, you can see that your README file is now tracked and staged: +إذا قمنا بتنفيذ الأمر `git status` مرة أخرى سنلاحظ أن الملف README أصبح متتبعاً وجاهزاً staged للقيام بعملية commit: $ git status # On branch master @@ -89,11 +88,11 @@ If you run your status command again, you can see that your README file is now t # new file: README # -You can tell that it’s staged because it’s under the “Changes to be committed” heading. If you commit at this point, the version of the file at the time you ran git add is what will be in the historical snapshot. You may recall that when you ran git init earlier, you then ran git add (files) — that was to begin tracking files in your directory. The git add command takes a path name for either a file or a directory; if it’s a directory, the command adds all the files in that directory recursively. +نستطيع معرفة بأن الملف staged من خلال ملاحظته تحت بند "changes to be comitted". إذا قمت بعمل commit في هذه اللحظة، سيقوم git بإضافة النسخة الحالية من الملف إلى snapshot. تذكر عندما قمنا بعمل git init سابقاً، ثم قمنا بإضافة الملفات عن طريق git add، كان ذلك للقيام ببدء تتبع الملفات في مجلد المشروع. يقبل الأمر git add مسار لملف أو لمجلد؛ فإذا كان المسار لمجلد سيقوم git بإضافة جميع الملفات والمجلدات ضمنه بشكل تعاودي recursively. -### Staging Modified Files ### +### تجهيز الملفات المعدلة ### -Let’s change a file that was already tracked. If you change a previously tracked file called `benchmarks.rb` and then run your `status` command again, you get something that looks like this: +لنقم بالتعديل على ملف قمنا بإضافته سابقاً. إذا قمنا مثلاً بالتعديل على ملف متتبع مسبقاً يدعى `benchmarks.rb` وقمنا بتنفيذ الأمر git status، سيكون الخرج مشابهاً للخرج التالي: $ git status # On branch master @@ -108,7 +107,7 @@ Let’s change a file that was already tracked. If you change a previously track # modified: benchmarks.rb # -The benchmarks.rb file appears under a section named “Changes not staged for commit” — which means that a file that is tracked has been modified in the working directory but not yet staged. To stage it, you run the `git add` command (it’s a multipurpose command — you use it to begin tracking new files, to stage files, and to do other things like marking merge-conflicted files as resolved). Let’s run `git add` now to stage the benchmarks.rb file, and then run `git status` again: +يظهر الملف benchmarks.rb تحت بند "changes not staged for commit" وهذا يعني أن الملف المُتتبّع قد خضع لعملية تعديل لكنه لم يخضع للتجهيز من أجل commit. للقيام بتجهيزه (أو تأشيره للإضافة إلى commit الجديد) يجب علينا تنفيذ الأمر `git add` (لاحظ بأنّه أمر متعدد الوظائف - نستطيع استخدامه لتتبع الملفات الجديدة، تجهيز الملفات من أجل commit، والقيام بأمور أخرى مثل حل الاعتراضات في حال القيام بدمج merge). لنقم بتنفيذ git add الآن لوضع benchmarks.rb بحالة staged، ومن ثم لنقم بتنفيذ الأمر git status لنرى ما الذي قد تغيّر: $ git add benchmarks.rb $ git status @@ -120,7 +119,7 @@ The benchmarks.rb file appears under a section named “Changes not staged for c # modified: benchmarks.rb # -Both files are staged and will go into your next commit. At this point, suppose you remember one little change that you want to make in benchmarks.rb before you commit it. You open it again and make that change, and you’re ready to commit. However, let’s run `git status` one more time: +كلا الملفين الآن جاهز للإدخال بعملية commit المقبلة. في هذه النقطة، لنفرض أنك تود القيام بتعديل على ملف benchmarks.rb قبل القيام بعملية commit، ستقوم بفتح الملف والتعديل عليه وأنك جاهز للقيام بعملية commit. لكن قبل ذلك، دعنا نقوم بتنفيذ الأمر git status مرة إضافية: $ vim benchmarks.rb $ git status @@ -137,7 +136,7 @@ Both files are staged and will go into your next commit. At this point, suppose # modified: benchmarks.rb # -What the heck? Now benchmarks.rb is listed as both staged and unstaged. How is that possible? It turns out that Git stages a file exactly as it is when you run the git add command. If you commit now, the version of benchmarks.rb as it was when you last ran the git add command is how it will go into the commit, not the version of the file as it looks in your working directory when you run git commit. If you modify a file after you run `git add`, you have to run `git add` again to stage the latest version of the file: +ما الذي يحصل؟ كيف أصبح benchmarks.rb موجوداً تحت التبويبين staged و unstaged؟ لقد اتضح لنا أنّ git يقوم بتجهيز الملف على حالته عند قيامك بتنفيذ الأمر git add. إذا قمت بعمل commit الآن، ستكون نسخة benchmarks.rb كما كانت عند قيامك بتنفيذ الأمر git add وليس النسخة الجديدة التي حصلنا عليها بعد قيامنا بتعديل الملف. لذا إذا قمنا بتعديل ملف قبل قيامنا بتنفيذ git add، وقبل القيام بعملية commit، علينا تجهيز الملف مرة أخرى لعملية commit، وذلك بتنفيذ الأمر git add مرة جديدة: $ git add benchmarks.rb $ git status @@ -149,26 +148,26 @@ What the heck? Now benchmarks.rb is listed as both staged and unstaged. How is t # modified: benchmarks.rb # -### Ignoring Files ### +### تجاهل الملفات ### -Often, you’ll have a class of files that you don’t want Git to automatically add or even show you as being untracked. These are generally automatically generated files such as log files or files produced by your build system. In such cases, you can create a file listing patterns to match them named .gitignore. Here is an example .gitignore file: +غالباً ما تود من git تجاهل صنف من الملفات بحث لا يقوم بإضافتها تلقائياً أو لا يظهرها بأنّها غير متتبعة. تكون هذه الملفات عادة ملفات مولدة بشكل تلقائي مثل ملفات log و الملفات الوسيطة التي تولدها أدوات التطوير لديك. في مثل هذه الحالات/ يمكن إنشاء ملف .gitignore يحوي على أنماط لأسماء الملفات التي نرغب بتجاهلها. هذا مثال عمّا قد يحتويه ملف .gitignore: $ cat .gitignore *.[oa] *~ -The first line tells Git to ignore any files ending in .o or .a — object and archive files that may be the product of building your code. The second line tells Git to ignore all files that end with a tilde (`~`), which is used by many text editors such as Emacs to mark temporary files. You may also include a log, tmp, or pid directory; automatically generated documentation; and so on. Setting up a .gitignore file before you get going is generally a good idea so you don’t accidentally commit files that you really don’t want in your Git repository. +أول سطر يقوم بتوجيه git إلى تجاهل أي ملفات ذات لواحق من النوع o أو a - ملفات الكائنات وملفات الأرشيف وهي ملفات وسيطة تولدها أدوات بناء الكود عادة. السطر الثاني يوجه git إلى تجاهل أي ملفات تنتهي بالرمز (~) والتي تكون ملفات مؤقتة عادةً تستخدمها بعض برامج تحرير الكود. قد ترغب أيضاً بإضافة مجلدات log و tmp أو pid؛ أو حتى ملفات التوثيق تلقائية التوليد (من الكود عادة)، وغيرها. ينصح بإضافة ملف .gitignore في بداية إنشاء repository حتى نتجنب إضافة بعض الملفات عن طريق الخطأ وتلويث respository. -The rules for the patterns you can put in the .gitignore file are as follows: +قواعد الأنماط التي يمكن وضعها ضمن ملف .gitignore هي كالتالي: -* Blank lines or lines starting with # are ignored. -* Standard glob patterns work. -* You can end patterns with a forward slash (`/`) to specify a directory. -* You can negate a pattern by starting it with an exclamation point (`!`). +* الأسطر التي تبدأ بالرمز (#) يتم تجاهلها. +* أنماط glob القياسية تعمل. +* يمكن إنهاء النمط برمز (/) للدلالة على أنه يستهدف مجلداً. +* يمكن نفي نمط ما عن طريق وضع علامة التعجب (!) في بداية السطر قبل النمط. -Glob patterns are like simplified regular expressions that shells use. An asterisk (`*`) matches zero or more characters; `[abc]` matches any character inside the brackets (in this case a, b, or c); a question mark (`?`) matches a single character; and brackets enclosing characters separated by a hyphen(`[0-9]`) matches any character between them (in this case 0 through 9) . +أنماط Glob عبارة عن نسخة مبسطة من Regular Expressions يتم استخدامها ضمن واجهة الأوامر shell. رمز النجمة (`*`) يطابق صفر-محرفاً أو أكثر. `[abc]` تطابق أي محارف ضمن الأقواس المربعة في هذه الحالة تكون a b c؛ علامة الاستفهام (?) تطابق محرفاً واحداً فقط؛ بينما تطابق الأقواس المربعة التي تحوي على محارف مفصولة بإشارة hyphen أي محرفاً يقع في المجال بين محرف البداية والنهاية - مثلا [0-9] يطابق محارف الأرقام بين 0 و 9 ضمناً. -Here is another example .gitignore file: +مثال عن ملف .gitignore: # a comment – this is ignored # no .a files @@ -182,11 +181,12 @@ Here is another example .gitignore file: # ignore doc/notes.txt, but not doc/server/arch.txt doc/*.txt -### Viewing Your Staged and Unstaged Changes ### +### مشاهدة التغيّرات المجهّزة والتغيّرات غير المجهّزة ### -If the `git status` command is too vague for you — you want to know exactly what you changed, not just which files were changed — you can use the `git diff` command. We’ll cover `git diff` in more detail later; but you’ll probably use it most often to answer these two questions: What have you changed but not yet staged? And what have you staged that you are about to commit? Although `git status` answers those questions very generally, `git diff` shows you the exact lines added and removed — the patch, as it were. +إذا لم تكتف بالمعلومات التي يقدمها لك أمر `git status` يمكنك استخدام أمر `git diff` للحصول على معلومات تفصيلية حول التغيرات التي طرأت على الملفات. سنقوم لاحقاً بالتعمق في هذا الأمر، لكن الآن سنكتفي بالإشارة إلى الاستخدامات الغالبة له؛ حيث أنك ستستخدمه غالباً للحصول على أجوبة على هذين السؤالين: ما الذي قمنا بالتعديل عليه ولم نجهزه بعد لعملية commit؟ ما الملفات التي أصبحت جاهزة للدخول في عملية commit المقبلة؟ +بالرغم من أنه يمكننا أن نحصل على هذه المعلومات باستخدام أمر `git status` إلا أنّ أمر `git diff` يوضح لنا التغيرات التي جرت على مستوى السطر والحرف - ما الذي قمنا بإضافته وما الذي أزلناه! -Let’s say you edit and stage the README file again and then edit the benchmarks.rb file without staging it. If you run your `status` command, you once again see something like this: +لنقل أنك قمت بالتعديل على ملف README مرة أخرى وأشرته للإضافة إلى عملية commit وقمت بالتعديل على ملف benchmarks.rb ولم تضفه إلى قائمة الملفات الجاهزة لعملية commit؛ إذا قمت بتنفيذ الأمر `status` ستشاهد مرة أخرى شيئاً من الشكل: $ git status # On branch master @@ -201,7 +201,7 @@ Let’s say you edit and stage the README file again and then edit the benchmark # modified: benchmarks.rb # -To see what you’ve changed but not yet staged, type `git diff` with no other arguments: +لترى ما قمت بالتعديل عليه ولم تجهزه للإضافة نفذ الأمر `git diff` بدون إضافات: $ git diff diff --git a/benchmarks.rb b/benchmarks.rb @@ -220,9 +220,9 @@ To see what you’ve changed but not yet staged, type `git diff` with no other a log = git.commits('master', 15) log.size -That command compares what is in your working directory with what is in your staging area. The result tells you the changes you’ve made that you haven’t yet staged. +يقوم هذا الأمر بعمل مقارنة بين الملفات ضمن مجلد العمل والملفات الموجودة في منطقة التعديلات المجهزة للإضافة staging area. وتخبرنا نتيجته بالتعديلات التي أجريناها ولم نقم بتجهيزها للإضافة إلى عملية commit المقبلة. -If you want to see what you’ve staged that will go into your next commit, you can use `git diff –-cached`. (In Git versions 1.6.1 and later, you can also use `git diff –-staged`, which may be easier to remember.) This command compares your staged changes to your last commit: +لمشاهدة الملفات ذات الحالة staged والتي ستدخل في عملية commit المقبلة، يمكن استخدام الأمر `git diff --cached` (بالنسبة للإصدارات 1.6.1 وما بعد من git يمكنك أيضاً استخدام الأمر `git diff --staged` )، كالتالي: $ git diff --cached diff --git a/README b/README @@ -237,9 +237,9 @@ If you want to see what you’ve staged that will go into your next commit, you + +Grit is a Ruby library for extracting information from a Git repository -It’s important to note that `git diff` by itself doesn’t show all changes made since your last commit — only changes that are still unstaged. This can be confusing, because if you’ve staged all of your changes, `git diff` will give you no output. +من الجدير بالذكر أن أمر `git diff` لوحده لا يقوم بعرض جميع التعديلات التي تمت من آخر commit - فهو يقوم بعرض فقط التعديلات التي لم تؤشر على أنها staged. ويمكن أن يسبب ذلك بعض الإرباك، حيث أنك إذا قمت بإضافة جميع التعديلات إلى قائمة staged فلن يقوم بعرض أي شي في خرج تنفيذه. -For another example, if you stage the benchmarks.rb file and then edit it, you can use `git diff` to see the changes in the file that are staged and the changes that are unstaged: +كمثال أيضاً، إذا قمنا بإضافة benchmarks.rb إلى قائمة staged ومن ثم قمنا بالتعديل عليه من جديد، يمكننا استخدام أمر `git diff` للحصول على لائحة بالتغييرات التي حصلت ولم تضف إلى قائمة staged كالتالي: $ git add benchmarks.rb $ echo '# test line' >> benchmarks.rb @@ -255,7 +255,6 @@ For another example, if you stage the benchmarks.rb file and then edit it, you c # modified: benchmarks.rb # -Now you can use `git diff` to see what is still unstaged $ git diff diff --git a/benchmarks.rb b/benchmarks.rb @@ -268,7 +267,7 @@ Now you can use `git diff` to see what is still unstaged ##pp Grit::GitRuby.cache_client.stats +# test line -and `git diff --cached` to see what you’ve staged so far: +وباستخدام `git diff --cached` نتمكن من رؤية ما تم تجهيزه للإضافة إلى عملية commit القادمة: $ git diff --cached diff --git a/benchmarks.rb b/benchmarks.rb @@ -287,16 +286,15 @@ and `git diff --cached` to see what you’ve staged so far: log = git.commits('master', 15) log.size -### Committing Your Changes ### +### القيام بعملية (اعتماد) commit للتغيّرات ### -Now that your staging area is set up the way you want it, you can commit your changes. Remember that anything that is still unstaged — any files you have created or modified that you haven’t run `git add` on since you edited them — won’t go into this commit. They will stay as modified files on your disk. -In this case, the last time you ran `git status`, you saw that everything was staged, so you’re ready to commit your changes. The simplest way to commit is to type `git commit`: +بعد اكمال تجهيز الملفات التي ترغب بإضافتها إلى النسخة snapshot الجديدة، يمكنك تنفيذ أمر commit ليتم اعتماد التعديلات التي أجريتها في سجل git. تذكر أنّ أي ملف لم يتم تجهيزه - سواء لم تقم بإضافته باستخدام الأمر git add بعد إنشاءه أو التعديل عليه - لن يدخل في هذه الإعتمادية، وستبقى على أنها ملفات تم تعديلها في مجلد العمل. أبسط طريقة لاعتماد التعديلات هي القيام بأمر `git commit` كالتالي: $ git commit -Doing so launches your editor of choice. (This is set by your shell’s `$EDITOR` environment variable — usually vim or emacs, although you can configure it with whatever you want using the `git config --global core.editor` command as you saw in Chapter 1). +تنفيذ هذا الأمر سيطلب منا إدخال رسالة عملية commit - عادة ما يتم فتح محرر النصوص المشار إليه بمتغير البيئة `$EDITOR`. يمكنك تهيئته عن طريق الأمر `git config --global core.editor` كما شاهدنا في الفصل الأول. -The editor displays the following text (this example is a Vim screen): +يقوم محرر النصوص بعرض هذه الشاشة (مثالنا باستخدام VIM): # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. @@ -311,22 +309,22 @@ The editor displays the following text (this example is a Vim screen): ~ ".git/COMMIT_EDITMSG" 10L, 283C -You can see that the default commit message contains the latest output of the `git status` command commented out and one empty line on top. You can remove these comments and type your commit message, or you can leave them there to help you remember what you’re committing. (For an even more explicit reminder of what you’ve modified, you can pass the `-v` option to `git commit`. Doing so also puts the diff of your change in the editor so you can see exactly what you did.) When you exit the editor, Git creates your commit with that commit message (with the comments and diff stripped out). +يمكنك ملاحظة أن رسالة عملية commit تحوي على خرج آخر عملية `git status` على شكل تعليقات بالإضافة إلى سطر فارغ في بداية الملف. يمكنك إزالة هذه التعليقات، أو يمكنك تركها لمساعدتك بتذكر ما قمت باعتماد تعديلاته. يمكنك الحصول على معلومات أكثر تفصلياً إذا قمت بتمرير الخيار `-v` إلى الأمر `git commit`. حيث يقوم ذلك بإضافة خرج أمر `git diff` إلى رسالة commit على شكل تعليقات أيضاً. عند إغلاق المحرر يقوم git بإنشاء commit ويتجاهل التعليقات. -Alternatively, you can type your commit message inline with the `commit` command by specifying it after a -m flag, like this: +علماً أنّه يمكنك كتابة رسالة الاعتمادية مباشرة من خلال تمرير الخيار `-m` إلى الأمر `git commit` على الشكل التالي: $ git commit -m "Story 182: Fix benchmarks for speed" [master]: created 463dc4f: "Fix benchmarks for speed" 2 files changed, 3 insertions(+), 0 deletions(-) create mode 100644 README -Now you’ve created your first commit! You can see that the commit has given you some output about itself: which branch you committed to (master), what SHA-1 checksum the commit has (`463dc4f`), how many files were changed, and statistics about lines added and removed in the commit. +مبروك، لقد قمت بعمل أول commit لك! يعطيك خرج العملية معلومات عنها: في أي فرع branch تم الإعتماد (هنا master)، ما قيمة هاش SHA-1 الخاصة بالعملية ( هنا `463dc4f`)، عدد الملفات التي تغيّرت، بالإضافة إلى إحصاءات حول الأسطر التي أضيفت وأزيلت في هذه العملية. -Remember that the commit records the snapshot you set up in your staging area. Anything you didn’t stage is still sitting there modified; you can do another commit to add it to your history. Every time you perform a commit, you’re recording a snapshot of your project that you can revert to or compare to later. +تذكر أنّ عملية commit تأخذ صورة عن الملفات في قائمة staged. أي شيء لم تقم بإضافته إلى هذه القائمة ما زال في مجلد العمل بحالة "معدل" modified؛ يمكنك القيام بإضافتهم من خلال عملية commit جديدة إلى التأريخ في git. نستنتج أنّه في كل عملية commit يقوم git بأخذ "صورة" snapshot عن المشروع يمكننا العودة لها لاحقاً أو مقارنتها أو غير ذلك.. -### Skipping the Staging Area ### +### تجاوز منطقة التجهيز Staging Area ### -Although it can be amazingly useful for crafting commits exactly how you want them, the staging area is sometimes a bit more complex than you need in your workflow. If you want to skip the staging area, Git provides a simple shortcut. Providing the `-a` option to the `git commit` command makes Git automatically stage every file that is already tracked before doing the commit, letting you skip the `git add` part: +منطقة التجهيز تكون أحياناً معقدة أكثر مما تحتاج في عملك إلا أنّها مفيدة لعمل commits تماماً كما تودهم أن يكونوا. إذا أردت تجاوز منطقة التجهيز، يوفر git اختصاراً بسيطاً لذلك. باستخدام الأمر `git commit -a` يقوم git بإضافة الملفات المتتبعة إلى منطقة التجهيز بشكل تلقائي، كأنك قمت بعمل `git add`: $ git status # On branch master @@ -339,13 +337,13 @@ Although it can be amazingly useful for crafting commits exactly how you want th [master 83e38c7] added new benchmarks 1 files changed, 5 insertions(+), 0 deletions(-) -Notice how you don’t have to run `git add` on the benchmarks.rb file in this case before you commit. +لاحظ بأنك لاتحتاج إلى تنفيذ الأمر `git add` على ملف benchmark.rb قبل القيام بعملية commit. -### Removing Files ### +### إزالة الملفات ### -To remove a file from Git, you have to remove it from your tracked files (more accurately, remove it from your staging area) and then commit. The `git rm` command does that and also removes the file from your working directory so you don’t see it as an untracked file next time around. +لحذف ملف من git، يجب عليك إزالته من قائمة الملفات المتتبعة (وبشكل أدق، إزالته من منطقة التجهيز) ومن ثم القيام بعملية commit. الأمر `git rm` يقوم بعمل ذلك كما يقوم بحذف الملف من مجلد العمل الخاص بك لذا لن تراه بعد الآن في قائمة الملفات غير المتتبعة في المرة المقبلة. -If you simply remove the file from your working directory, it shows up under the “Changes not staged for commit” (that is, _unstaged_) area of your `git status` output: +إذا قمت بإزالة الملف من مجلد العمل، يظهر تحت بند "تعديلات غير مجهزة للاعتماد" (أي _unstaged_) من خرج الأمر `git status`: $ rm grit.gemspec $ git status @@ -357,7 +355,7 @@ If you simply remove the file from your working directory, it shows up under the # deleted: grit.gemspec # -Then, if you run `git rm`, it stages the file’s removal: +فإذا قمت بتنفيذ أمر `git rm` يقوم بتجهيز عملية الحذف ليتم اعتمادها: $ git rm grit.gemspec rm 'grit.gemspec' @@ -370,31 +368,31 @@ Then, if you run `git rm`, it stages the file’s removal: # deleted: grit.gemspec # -The next time you commit, the file will be gone and no longer tracked. If you modified the file and added it to the index already, you must force the removal with the `-f` option. This is a safety feature to prevent accidental removal of data that hasn’t yet been recorded in a snapshot and that can’t be recovered from Git. +وفي المرة المقبلة التي ستقوم فيها بعمل commit، سيتم إزالة الملف من قائمة التتبع. إذا قمت مسبقاً بتعديل الملف وإضفته إلى الفهرس، يجب عليه تنفيذ عملية الحذف قسرياً وذلك بإضافة الخيار `-f`. يتم اتباع هذه الطريقة بغية حماية البيانات من أية عمليات حذف "عرضية" لملفات لم يتم تسجيلها ضمن git ولايمكن استعادتها بعد ذلك. -Another useful thing you may want to do is to keep the file in your working tree but remove it from your staging area. In other words, you may want to keep the file on your hard drive but not have Git track it anymore. This is particularly useful if you forgot to add something to your `.gitignore` file and accidentally added it, like a large log file or a bunch of `.a` compiled files. To do this, use the `--cached` option: +أما إذا أردت إزالة الملف من منطقة التجهيز مع الحفاظ عليه في مجلد العمل (أي إزالته من تتبع git مع بقاءه على وسيطة التخزين) - وهو شيء مفيد إذا قمت بنسيان إضافة شيء ما إلى ملف `.gitignore` وأضفته عن طريق الخطأ ؛ كملف log كبير مثلاً - استخدم الخيار `--cached` مع الأمر `git rm` كالتالي: $ git rm --cached readme.txt -You can pass files, directories, and file-glob patterns to the `git rm` command. That means you can do things such as +يمكنك تمرير أسماء ملفات، مجلدات، وأنماط glob للأمر `git rm`. وهذا يعني بأنه يمكننا عمل أشياء كالتالي: $ git rm log/\*.log -Note the backslash (`\`) in front of the `*`. This is necessary because Git does its own filename expansion in addition to your shell’s filename expansion. This command removes all files that have the `.log` extension in the `log/` directory. Or, you can do something like this: +لاحظ الشرطة العكسية (`\`) قبل رمز النجمة `*`. إنّها ضرورية لأن git يقوم بعمل توسعة الأسماء الخاصة به بالإضافة إلى التوسعة الخاصة بسطر الأوامر. هذا الأمر يقوم بحذف كافة الملفات التي تملك اللاحقة `.log` في مجلد `/log`. أو يمكنك عمل شيء كالتالي: $ git rm \*~ -This command removes all files that end with `~`. +وهذا الأمر يقوم بحذف كافة الملفات المنتهية بالمحرف `~`. -### Moving Files ### +### نقل الملفات ### -Unlike many other VCS systems, Git doesn’t explicitly track file movement. If you rename a file in Git, no metadata is stored in Git that tells it you renamed the file. However, Git is pretty smart about figuring that out after the fact — we’ll deal with detecting file movement a bit later. +على خلاف أغلب أنظمة إدارة الإصدارات VCS الأخرى، لا يقوم git بتعقب حركة الملفات بشكل صريح. إذا قمت بإعادة تسمية ملف ضمن git، لايتم تسجيل أي بيانات وصفية metadata في git تقوم بأنك قمت بإعادة تسمية الملف. لكن، git ذكي جداً في استعياب ذلك - وسنقوم بمناقشة الأمر بعد قليل. -Thus it’s a bit confusing that Git has a `mv` command. If you want to rename a file in Git, you can run something like +إذا أردت القيام بإعادة تسمية ملف يمكنك استخدام أمر `mv` في git كالتالي: $ git mv file_from file_to -and it works fine. In fact, if you run something like this and look at the status, you’ll see that Git considers it a renamed file: +إذا قمنا بتنفيذ الأمر والنظر إلى خرج أمر `git status`: $ git mv README.txt README $ git status @@ -407,23 +405,23 @@ and it works fine. In fact, if you run something like this and look at the statu # renamed: README.txt -> README # -However, this is equivalent to running something like this: +وهو مكافئ للقيام بتنفيذ الأوامر التالي على التسلسل: $ mv README.txt README $ git rm README.txt $ git add README -Git figures out that it’s a rename implicitly, so it doesn’t matter if you rename a file that way or with the `mv` command. The only real difference is that `mv` is one command instead of three — it’s a convenience function. More important, you can use any tool you like to rename a file, and address the add/rm later, before you commit. +يدرك git بأنك قمت بعملية إعادة تسمية، لذا فالإختلاف الوحيد بين الطريقتين هو أنّ `git mv` عبارة عن أمر واحد، وليس ثلاثة أوامر. يمكن الاستفادة من هذه الخاصة باستخدام أية أدوات للقيام بعمليات إعادة التسمية، واستخدام add/rm قبل القيام بعملية commit. -## Viewing the Commit History ## +## مراجعة تأريخ عمليات commit ## -After you have created several commits, or if you have cloned a repository with an existing commit history, you’ll probably want to look back to see what has happened. The most basic and powerful tool to do this is the `git log` command. +بعد قيامك بعدد من عمليات الاعتماد commit، أو استنساخ repository بسجل تأريخ، ربما ستود إلقاء نظرة على ما جرى. أبسط وأقوى أداة لعمل ذلك هي الأمر `git log`. -These examples use a very simple project called simplegit that I often use for demonstrations. To get the project, run +هذه الأمثلة تستخدم مشروع بسيط جداً يدعى simplegit أقوم باستخدامه في عمليات العرض بأغلب الأحيان. للحصول على المشروع قم باستنساخه عن موقع github كالتالي: git clone git://github.com/schacon/simplegit-progit.git -When you run `git log` in this project, you should get output that looks something like this: +عندما تقوم بعمل `git log` ضمن المشروع، سيظهر لديك خرج مشابه للتالي: $ git log commit ca82a6dff817ec66f44342007202690a93763949 @@ -444,11 +442,11 @@ When you run `git log` in this project, you should get output that looks somethi first commit -By default, with no arguments, `git log` lists the commits made in that repository in reverse chronological order. That is, the most recent commits show up first. As you can see, this command lists each commit with its SHA-1 checksum, the author’s name and e-mail, the date written, and the commit message. +بتنفيذ الأمر بدون بارمترات، يقوم git بعرض عمليات commit في repository بترتيب زمني معكوس - من الأحدث إلى الأقدم. كما يقوم بعرض بجانب كل commit هاش SHA-1 checksum الخاص بها، اسم وبريد الكاتب الإلكتروني، تاريخ الاعتماد، ورسالة الاعتماد. -A huge number and variety of options to the `git log` command are available to show you exactly what you’re looking for. Here, we’ll show you some of the most-used options. +يمكن إرفاق الأمر `git log` بعدد كبير من الخيارات للحصول على المعلومات التي نريدها بالضبط.. تجد في الأسفل مثالاً عن أكثر الخيارات استخداماً. -One of the more helpful options is `-p`, which shows the diff introduced in each commit. You can also use `-2`, which limits the output to only the last two entries: +أحد أهم الخيارات هو `-p`، والذي يقوم بإظهار الفوارق المستحدثة بين عمليات commit المختلفة. يمكن أيضاً استخدام الخيار `-2` ليحد خرج النتيجة إلى آخر عمليتين: $ git log –p -2 commit ca82a6dff817ec66f44342007202690a93763949 @@ -488,8 +486,7 @@ One of the more helpful options is `-p`, which shows the diff introduced in each -end \ No newline at end of file -This option displays the same information but with a diff directly following each entry. This is very helpful for code review or to quickly browse what happened during a series of commits that a collaborator has added. -You can also use a series of summarizing options with `git log`. For example, if you want to see some abbreviated stats for each commit, you can use the `--stat` option: +هذا الخيار يعرض نفس المعلومات بالإضافة خرج diff بعده مباشرة. فهو مهم جداً من أجل مراجعة الكود واستعراض ما الذي تغير بشكل سريع ضمن سلسلة من عمليات commit. يمكنك أيضاً استخدام خيارات للتلخيص مع أمر `git log`. على سبيل المثال، إذا أردت رؤية بعض الإحصاءات المختصرة لكل commit، يمكنك استخدام الخيار `stat`: $ git log --stat commit ca82a6dff817ec66f44342007202690a93763949 @@ -521,43 +518,43 @@ You can also use a series of summarizing options with `git log`. For example, if lib/simplegit.rb | 25 +++++++++++++++++++++++++ 3 files changed, 54 insertions(+), 0 deletions(-) -As you can see, the `--stat` option prints below each commit entry a list of modified files, how many files were changed, and how many lines in those files were added and removed. It also puts a summary of the information at the end. -Another really useful option is `--pretty`. This option changes the log output to formats other than the default. A few prebuilt options are available for you to use. The oneline option prints each commit on a single line, which is useful if you’re looking at a lot of commits. In addition, the `short`, `full`, and `fuller` options show the output in roughly the same format but with less or more information, respectively: +كما ترى باستخدام الخيار `--stat` يتم عرض قائمة من الملفات المعدلة، عدد الملفات التي تغيرت، وعدد الأسطر التي أضيفت أو أزيلت. كما يضع ملخصاً للمعلومات في النهاية. +يوجد خيار مفيد آخر وهو `--pretty`. هذا الخيار يغير خرج السل إلى صيغ غير الافتراضية. يوجد بعضها مركب مسبقاً. مثلاً `oneline` يقوم بطباعة كل commit على سطر لوحدها، وهذا أمر مفيد في حال كنت تنظر إلى العديد من عمليات commit. بالإضافة إلى `short`، `full` و `fuller` والتي تعرض خرجاً تقريباً بنفس الصيغة مع معلومات أكثر أو أقل: $ git log --pretty=oneline ca82a6dff817ec66f44342007202690a93763949 changed the version number 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 removed unnecessary test code a11bef06a3f659402fe7563abf99ad00de2209e6 first commit -The most interesting option is `format`, which allows you to specify your own log output format. This is especially useful when you’re generating output for machine parsing — because you specify the format explicitly, you know it won’t change with updates to Git: +أكثر الخيارات أهمية هو `format`، والذي يسمح لك بتحديد صيغة الخرج بشكل صريح بما يتناسب مع إعرابها آلياً - حيث أنك تعرف أنّه لن يتغير عند التحديث إلى git: $ git log --pretty=format:"%h - %an, %ar : %s" ca82a6d - Scott Chacon, 11 months ago : changed the version number 085bb3b - Scott Chacon, 11 months ago : removed unnecessary test code a11bef0 - Scott Chacon, 11 months ago : first commit -Table 2-1 lists some of the more useful options that format takes. - - Option Description of Output - %H Commit hash - %h Abbreviated commit hash - %T Tree hash - %t Abbreviated tree hash - %P Parent hashes - %p Abbreviated parent hashes - %an Author name - %ae Author e-mail - %ad Author date (format respects the –date= option) - %ar Author date, relative - %cn Committer name - %ce Committer email - %cd Committer date - %cr Committer date, relative - %s Subject - -You may be wondering what the difference is between _author_ and _committer_. The author is the person who originally wrote the work, whereas the committer is the person who last applied the work. So, if you send in a patch to a project and one of the core members applies the patch, both of you get credit — you as the author and the core member as the committer. We’ll cover this distinction a bit more in Chapter 5. - -The oneline and format options are particularly useful with another `log` option called `--graph`. This option adds a nice little ASCII graph showing your branch and merge history, which we can see our copy of the Grit project repository: +الجدول 2-1 يعرض بعض الخيارات المفيدة التي يمكن إضافتها إلى الصيغة. + + الخيار وصف الخرج + %H Commit هاش + %h الهاش الاعتمادي المختصر + %T هاش الشجرة + %t هاش الشجرة المختصر + %P هاشات الوالد + %p هاشات الوالد المختصرة + %an اسم الكاتب + %ae بريد الكاتب الإلكتروني + %ad تاريخ الكاتب (يراعي الصيغة –date= option) + %ar تاريخ الكاتب - نسبياً + %cn اسم منفذ الاعتماد + %ce بريد منفذ الاعتماد الإلكتروني + %cd تاريخ منفذ الاعتماد + %cr تاريخ منفذ الاعتماد - نسبياً + %s العنوان + +قد تتسائل عن الاختلاف بين _الكاتب_ AUTHOR و _منفذ الاعتماد_ COMMITTER. الكاتب هو الشخص الذي كتب العمل بداية، بينما منفذ الاعتماد هو آخر شخص طبق العمل. لذا، إذا أرسلت باتشاً إلى مشروع وأحد المطورين الرئيسين قام بتطبيق الباتش، تأخذان كلاكما الاعتمادية - أنت ككاتب وهو كمنفذ اعتماد. + +وتكون هذه الخيارات مفيدة أكثر بالترافق مع الخيار `--graph`. حيث يضيف هذا الأمر غراف ASCII بسيط يوضح تأريخ الأفرع و الدمج، لاحظ التالي: $ git log --pretty=format:"%h %s" --graph * 2d3acf9 ignore errors from SIGCHLD on trap @@ -571,43 +568,43 @@ The oneline and format options are particularly useful with another `log` option * d6016bc require time for xmlschema * 11d191e Merge branch 'defunkt' into local -Those are only some simple output-formatting options to `git log` — there are many more. Table 2-2 lists the options we’ve covered so far and some other common formatting options that may be useful, along with how they change the output of the log command. +يوجد مجموعة من الخيارات البسيطة مع أمر `git log`. يوضح الجدول 2-2 قائمة من الخيارات التي قمنا بتغطيتها حتى الآن وبعض صيغ التنسيق الشائعة والتي قد تكون مفيدة، وبجانبها شرح مبسط عن التغيير الذي تجريه على الخرج. - Option Description - -p Show the patch introduced with each commit. - --stat Show statistics for files modified in each commit. + الخيار الوصف + -p يظهر الباتش المدخل مع كل عملية commit. + --stat يظهر إحصاءات حول التعديلات التي حصلت على الملفات مع كل عملية commit. --shortstat Display only the changed/insertions/deletions line from the --stat command. - --name-only Show the list of files modified after the commit information. - --name-status Show the list of files affected with added/modified/deleted information as well. - --abbrev-commit Show only the first few characters of the SHA-1 checksum instead of all 40. + --name-only يظهر قائمة الملفات المعدلة. + --name-status يظهر قائمة الملفات المعدلة عن طريق الإضافة والحذف وغير ذلك. + --abbrev-commit يظهر أول مجموعة من هاش SHA-1 بدلاً عن كامل الأحرف 40. --relative-date Display the date in a relative format (for example, “2 weeks ago”) instead of using the full date format. - --graph Display an ASCII graph of the branch and merge history beside the log output. + --graph عرض غراف ASCII مع الخرج يظهر عمليات التفريع و الدمج. --pretty Show commits in an alternate format. Options include oneline, short, full, fuller, and format (where you specify your own format). -### Limiting Log Output ### +### تحديد خرج السجل ### -In addition to output-formatting options, git log takes a number of useful limiting options — that is, options that let you show only a subset of commits. You’ve seen one such option already — the `-2` option, which show only the last two commits. In fact, you can do `-`, where `n` is any integer to show the last `n` commits. In reality, you’re unlikely to use that often, because Git by default pipes all output through a pager so you see only one page of log output at a time. +بالإضافة تحديد شكل الخرج، يسمح git بأخذ مجموعة جزئية فقط من الخرج. وقد قمت بمشاهدة ذلك مسبقاً - الخيار `-2` المستخدم لعرض آخر عمليتي commit. في الواقع يمكنك استخدام `-` حيث `n` هي عدد صحيح لعرض آخر `n` عملية commit. في الحقيقة، لن تستخدمها على الغالب، لأن git يقوم بتمرير كامل الخرج لبرنامج تصفح لتتمكن من تصفح عمليات commit صفحة صفحة. -However, the time-limiting options such as `--since` and `--until` are very useful. For example, this command gets the list of commits made in the last two weeks: +من الخيارات الهامة جداً، المحددات الزمنية مثل `--since` و `--until`. على سبيل المثال، هذا الأمر يعطيك قائمة بعمليات commit التي حصلت في آخر أسبوعين: $ git log --since=2.weeks -This command works with lots of formats — you can specify a specific date (“2008-01-15”) or a relative date such as “2 years 1 day 3 minutes ago”. +ويعمل هذا الأمر مع أنواع كثيرة من الصيغ - يمكنك تحديد تاريخ محدد ("2008-01-15") أو تاريخ نسبي مثل "2 years 1 day 3 minutes ago". -You can also filter the list to commits that match some search criteria. The `--author` option allows you to filter on a specific author, and the `--grep` option lets you search for keywords in the commit messages. (Note that if you want to specify both author and grep options, you have to add `--all-match` or the command will match commits with either.) +يكطمط أيضاً تصفية قائمة عمليات commit من خلال محددات البحث. مثلاً خيار `--author` يقوم بتصفية النتائج وفق كاتب محدد، و `--grep` يقوم بالفلترة عن طريق كلمة مفتاحية. (لاحظ أنّه إذا قمت بإضافة خياراي author و grep، يجب عليك إضافة الخيار `--all-match` أو سيقوم git بعمل مطابقة مع أحدهما فقط). -The last really useful option to pass to `git log` as a filter is a path. If you specify a directory or file name, you can limit the log output to commits that introduced a change to those files. This is always the last option and is generally preceded by double dashes (`--`) to separate the paths from the options. +آخر الخيارات الهامة التي يمكن تمريرها إلى الأمر `git log` كمصناف هي المسار. إذا قمت بتحديد مجلد أو اسم ملف، يمكنك تحديد الخرج إلى عمليات commit التي آثرت في هذا المسار. ودائماً ما يكون آخر خيار يوضع في `log` ويسبق بداشين double dashes (`--`) ليفصل المسارات عن الخيارات. -In Table 2-3 we’ll list these and a few other common options for your reference. +في الجدول 2-3 - نعرض الخيارات التي يمكن إضافتها مع log. - Option Description - -(n) Show only the last n commits - --since, --after Limit the commits to those made after the specified date. - --until, --before Limit the commits to those made before the specified date. - --author Only show commits in which the author entry matches the specified string. - --committer Only show commits in which the committer entry matches the specified string. + خيار وصف + -(n) يظهر آن n عملية commit. + --since, --after تحديد عمليات commit بعد التاريخ الذي يتلوها. + --until, --before تحديد عمليات commit حتى التاريخ الذي يتلوها. + --author فقط أظهر عمليات commit التابعة لهذا الكاتب. + --committer فقط أظهر عمليات commit التابعة لهذا المعتمد. -For example, if you want to see which commits modifying test files in the Git source code history were committed by Junio Hamano and were not merges in the month of October 2008, you can run something like this: +على سبيل المثال، إذا أردت رؤية أي عمليات commit عدلت ملفات الاختبار في تأريخ الكود المصدري والتي قام Junio Hamano بعملها ولم يتم دمجها في شهر أوكتوبر 2008، يمكن كتابة هذا الأمر: $ git log --pretty="%h - %s" --author=gitster --since="2008-10-01" \ --before="2008-11-01" --no-merges -- t/ @@ -618,7 +615,7 @@ For example, if you want to see which commits modifying test files in the Git so 51a94af - Fix "checkout --track -b newbranch" on detac b0ad11e - pull: allow "git pull origin $something:$cur -Of the nearly 20,000 commits in the Git source code history, this command shows the 6 that match those criteria. +من بين 20 ألف عملية commit تقريباً في تأريخ git الخاص بهذا الكود المصدري، أظهر الأمر فقط عمليات الاعتماد الستة المطابقة لمحددات البحث. ### Using a GUI to Visualize History ### diff --git a/az/01-introduction/01-chapter1.markdown b/az/01-introduction/01-chapter1.markdown index e45515bdd..d2cea2626 100644 --- a/az/01-introduction/01-chapter1.markdown +++ b/az/01-introduction/01-chapter1.markdown @@ -1,43 +1,43 @@ # Başlanğıc # -Bu bölmə size git haqqında başlıca məlumatları çattırmağı hədəfləyir. We will begin at the beginning by explaining some background on version control tools, then move on to how to get Git running on your system and finally how to get it setup to start working with. At the end of this chapter you should understand why Git is around, why you should use it and you should be all setup to do so. +Bu bölmə size git haqqında başlıca məlumatları çattırmağı hədəfləyir. İşə başlamazdan əvvəl version nəzarət vasitəsinin bəzi fon məlumatlarını açıqlayaraq başlayacağıq, daha sonra Git quraşdırılmanının necə ediləcəyini, ən son olaraq da vasitənin konfiqurasiya və istifadəsini açıqlayacağıq. Bu hissənin sonunda Git'in varlıq səbəbini və niyə onu istifadə etməniz lazım olduğunu anlayacaq, Git'i istifadə etmeye başlamaq üçün quraşdırma bitirmiş olacaqsınız. -## About Version Control ## +## Versiya Nəzarət Haqqında ## -What is version control, and why should you care? Version control is a system that records changes to a file or set of files over time so that you can recall specific versions later. Even though the examples in this book show software source code as the files under version control, in reality any type of file on a computer can be placed under version control. +Versiya nəzarəti nədir və nə işə yarayar? Versiya nəzarəti, Bir ya da daha çox fayl üzərində edilən dəyişiklikləri yazan və daha sonra müəyyən bir distributivə geri dönə bilmənizi təmin edən bir sistemdir. Bu kitabdakı nümunələrdə proqram qaynaq kod fayllarının versiya idarəsini edəcəksiniz, nə var ki, əslində versiyası idarəsini demək olar ki hər növdən fayl üçün istifadə edə bilərsiniz. -If you are a graphic or web designer and want to keep every version of an image or layout (which you certainly would), it is very wise to use a Version Control System (VCS). A VCS allows you to: revert files back to a previous state, revert the entire project back to a previous state, compare changes over time, see who last modified something that might be causing a problem, who introduced an issue and when, and more. Using a VCS also means that if you screw things up or lose files, you can generally recover easily. In addition, you get all this for very little overhead. +Bir grafik və ya web dizayn tək və bir vizual və ya dizaynın dəyişik versiyalarını qorumaq istəyirsinizsə (ki ehtimalla bunu etmək istəyərsiniz), bir Versiya Nəzarət Sistemi (VNS) istifadə etməniz çox ağıllıca olacaq. VNS, faylların və ya bütün layihənin keçmişdəki müəyyən bir versiyaya daxil olmağa, zaman içində edilən dəyişiklikləri müqayisə etməyinizi, problemə səbəb olan şeydə ən son kimin dəyişiklik etdiyini, müəyyən bir səhvi kimin, nə vaxt sistemə daxil etdiyini və daha başqa bir çox şeyi görə bilməyinizi təmin edər. Digər tərəfdən, VNS istifadə etmək, bir səhv etdikdə və ya bəzi faylları səhvən sildiyiniz də vəziyyəti asanlıqla kompensasiya etmənizə köməkçi olar. Üstəlik, bütün bunlar sizə əhəmiyyətli bir əlavə yük də gətirməz. -### Local Version Control Systems ### +### Lokal Sürüm Nəzarət Sistemləri ### -Many people’s version-control method of choice is to copy files into another directory (perhaps a time-stamped directory, if they’re clever). This approach is very common because it is so simple, but it is also incredibly error prone. It is easy to forget which directory you’re in and accidentally write to the wrong file or copy over files you don’t mean to. +Əksəriyyəti faylları bir qovluğa (ağılları başlarındaysa tarix və zaman məlumatını də daxil olmaqla bir qovluğa) kopiyalayaraq versiyas nəzarətini etməyi seçər. Bu yanaşma çox məşhurdur, çünki çox asandır; amma eyni zamanda səhvlərə də ala bildiyinə açıqdır. Hansı qovluqda olduğunuzu unudub səhv fayla yaza ya da istəmədiyiniz faylların üstünə kopiyalama edə bilərsiniz. -To deal with this issue, programmers long ago developed local VCSs that had a simple database that kept all the changes to files under revision control (see Figure 1-1). +Bu problemlə baş edə bilmək üçün, proqramçılar uzun zaman əvvəl, fayllardakı bütün dəyişiklikləri versiya nəzarətinə alan sadə bir veri bazasına sahib olan lokal VNS'leri inkişaf etdirdilər (bax Göstərici 1-1). Insert 18333fig0101.png -Figure 1-1. Local version control diagram. +Göstərici 1-1. Lokal Sürüm Nəzarət diaqramı. -One of the more popular VCS tools was a system called rcs, which is still distributed with many computers today. Even the popular Mac OS X operating system includes the rcs command when you install the Developer Tools. This tool basically works by keeping patch sets (that is, the differences between files) from one change to another in a special format on disk; it can then re-create what any file looked like at any point in time by adding up all the patches. +Ən məşhur VNS vasitələrindən biri, bu gün hələ çox kompüterə yüklenmiş olaraq yayılan, RCS adında bir sistem idi. Məşhur Mac OS X əməliyyat sistemi belə, Developer Tools'u yüklediğinizde, RCS əmrini qurmaqdadır. Bu vasitə, iki versiyası arasındakı yamaqları (yəni, fayllar arasındakı fərqləri) xüsusi bir şəkildə diskə yazar; daha sonra, bu yamaqları bir-birinə əlavə, bir faylın müəyyən bir distributivdəki görünüşünü yenidən meydana gətirər. -### Centralized Version Control Systems ### +### Mərkəzi Versiya Nəzarət Sistemləri ### -The next major issue that people encounter is that they need to collaborate with developers on other systems. To deal with this problem, Centralized Version Control Systems (CVCSs) were developed. These systems, such as CVS, Subversion, and Perforce, have a single server that contains all the versioned files, and a number of clients that check out files from that central place. For many years, this has been the standard for version control (see Figure 1-2). +İnsanların qarşılaşdığı ikinci böyük problem, başqa sistemlərdəki proqramçılar ilə birlikdə iş ehtiyacından irəli gəlir. Bu problemlə başa çıxa bilmək üçün, Mərkəzi Versiya Nəzarət Sistemləri (MVNS) inkişaf etdirilmişdir. Bu sistemlər, məsələn CVS, Subversion və Perforce, versiyası idarəsinə alınan bütün faylları tutan bir server və bu serverdən faylları seçərək alan (check out) alıcını meydana gələr. Bu üsul, illərcə, versiyası idarəsində standart üsul olaraq qəbul gördü (bax Göstərici 1-2). Insert 18333fig0102.png -Figure 1-2. Centralized version control diagram. +Göstərici 1-2. Mərkəzi Versiya Nəzarət diaqramı. -This setup offers many advantages, especially over local VCSs. For example, everyone knows to a certain degree what everyone else on the project is doing. Administrators have fine-grained control over who can do what; and it’s far easier to administer a CVCS than it is to deal with local databases on every client. +Bu üsulun, xüsusilə lokal VNS lere görə, çox sayda üstünlüyü vardır. Məsələn, bir projedeki hər kəs, digərlərinin nə etdiyindən müəyyən ölçüdə xəbərdardır. Sistem idarəçiləri kimin hansı səlahiyyətlərə sahib olacağını olduqca detallı şəkildə təşkil; üstəlik bir MVNS'yi idarə, hər alıcını ayrı-ayrı heyəti olan yerli bazalarını idarə görə çox daha asandır. -However, this setup also has some serious downsides. The most obvious is the single point of failure that the centralized server represents. If that server goes down for an hour, then during that hour nobody can collaborate at all or save versioned changes to anything they’re working on. If the hard disk the central database is on becomes corrupted, and proper backups haven’t been kept, you lose absolutely everything—the entire history of the project except whatever single snapshots people happen to have on their local machines. Local VCS systems suffer from this same problem—whenever you have the entire history of the project in a single place, you risk losing everything. +Nə var ki, bu üsulun də ciddi bəzi çətinlikləri vardır. Ən aşkar çətinlik, mərkəzi serverin işləməməsi vəziyyətində ortaya çıxacaq qırılma nöqtəsi problemidir. Server bir saatlığına çökəcək olsa, o bir saat boyunca istifadəçilərin işlərini sistemə köçürmələri ya da çalışdıqları şeylərin sürümlenmiş surətlərini saxlamaq mümkün olmayacaq. Mərkəzi bazanın sabit diski pozulacaq olsa, ehtiyyat da olması lazım olduğu kimi edilməmişsə, əlinizdəki hər şeyi -projenin, istifadəçilərin kompüterlərində qalan lokal yaddaş kopiyaları (snapshot) xaricindəki bütün tarihçesini- itirərsiniz. Yerli VNS'ler də bu problemdən çəkir -projenin bütün tarixçəsini tək bir yerdə tutduğunuz müddətcə hər şeyi itirmə riskiniz var. -### Distributed Version Control Systems ### +### Paylanmış Versiya Nəzarət Sistemləri ### -This is where Distributed Version Control Systems (DVCSs) step in. In a DVCS (such as Git, Mercurial, Bazaar or Darcs), clients don’t just check out the latest snapshot of the files: they fully mirror the repository. Thus if any server dies, and these systems were collaborating via it, any of the client repositories can be copied back up to the server to restore it. Every checkout is really a full backup of all the data (see Figure 1-3). +Bu nöqtədə Paylanmış Versiya Nəzarət Sistemləri (PVNS) dövrəyə girər. Bir PVNS'de (Git, Mercurial, Bazaar ya da Darcs nümunələrində olduğu kimi), müştərilər (istifadəçilər) faylların yalnız ən son yaddaş surətlərini almaqla qalmazlar: proqram hovuzunu (repository) tamamilə yansılalar (kopyalarlar).Beləcə, serverlərdən biri çöksə, və o server üzərindən ortaq iş icra edən sistemlər varsa, alıcını birinin proqram hovuzu serverə geri yüklənərək sistem qurtarıla bilər. Hər seçmə (checkout) əməliyyatı əsasında bütün məlumatın yedeklenmesiyle nəticələnər(bax Göstərici 1-3). Insert 18333fig0103.png -Figure 1-3. Distributed version control diagram. +Göstərici 1-3. Paylanmış Versiya Nəzarət diaqramı. -Furthermore, many of these systems deal pretty well with having several remote repositories they can work with, so you can collaborate with different groups of people in different ways simultaneously within the same project. This allows you to set up several types of workflows that aren’t possible in centralized systems, such as hierarchical models. +Dahası, bu sistemlerden çoğu birden çok uzak uçbirimdeki yazılım havuzuyla rahatlıkla çalışır, böylece, aynı proje için aynı anda farklı insan topluluklarıyla farklı biçimlerde ortak çalışmalar yürütebilirsiniz. Bu, birden çok iş akışı ile çalışabilmenizi sağlar, ki bu merkezi sistemlerde (hiyerarşik modeller gibi) mümkün değildir. ## A Short History of Git ## @@ -161,9 +161,9 @@ Or if you’re on a Debian-based distribution like Ubuntu, try apt-get: ### Installing on Mac ### -There are two easy ways to install Git on a Mac. The easiest is to use the graphical Git installer, which you can download from the Google Code page (see Figure 1-7): +There are two easy ways to install Git on a Mac. The easiest is to use the graphical Git installer, which you can download from the SourceForge page (see Figure 1-7): - http://code.google.com/p/git-osx-installer + http://sourceforge.net/projects/git-osx-installer/ Insert 18333fig0107.png Figure 1-7. Git OS X installer. diff --git a/az/02-git-basics/01-chapter2.markdown b/az/02-git-basics/01-chapter2.markdown index 4e177b56a..7f405674a 100644 --- a/az/02-git-basics/01-chapter2.markdown +++ b/az/02-git-basics/01-chapter2.markdown @@ -55,7 +55,7 @@ The main tool you use to determine which files are in which state is the `git st $ git status # On branch master - nothing to commit (working directory clean) + nothing to commit, working directory clean This means you have a clean working directory — in other words, there are no tracked and modified files. Git also doesn’t see any untracked files, or they would be listed here. Finally, the command tells you which branch you’re on. For now, that is always `master`, which is the default; you won’t worry about it here. The next chapter will go over branches and references in detail. diff --git a/az/04-git-server/01-chapter4.markdown b/az/04-git-server/01-chapter4.markdown index 8733fe40a..c51b6a74d 100644 --- a/az/04-git-server/01-chapter4.markdown +++ b/az/04-git-server/01-chapter4.markdown @@ -70,7 +70,7 @@ The negative aspect of SSH is that you can’t serve anonymous access of your re ### The Git Protocol ### -Next is the Git protocol. This is a special daemon that comes packaged with Git; it listens on a dedicated port (9418) that provides a service similar to the SSH protocol, but with absolutely no authentication. In order for a repository to be served over the Git protocol, you must create the `git-export-daemon-ok` file — the daemon won’t serve a repository without that file in it — but other than that there is no security. Either the Git repository is available for everyone to clone or it isn’t. This means that there is generally no pushing over this protocol. You can enable push access; but given the lack of authentication, if you turn on push access, anyone on the internet who finds your project’s URL could push to your project. Suffice it to say that this is rare. +Next is the Git protocol. This is a special daemon that comes packaged with Git; it listens on a dedicated port (9418) that provides a service similar to the SSH protocol, but with absolutely no authentication. In order for a repository to be served over the Git protocol, you must create the `git-daemon-export-ok` file — the daemon won’t serve a repository without that file in it — but other than that there is no security. Either the Git repository is available for everyone to clone or it isn’t. This means that there is generally no pushing over this protocol. You can enable push access; but given the lack of authentication, if you turn on push access, anyone on the internet who finds your project’s URL could push to your project. Suffice it to say that this is rare. #### The Pros #### @@ -369,7 +369,7 @@ Gitosis requires some Python tools, so first you have to install the Python setu Next, you clone and install Gitosis from the project’s main site: - $ git clone git://eagain.net/gitosis.git + $ git clone https://github.com/tv42/gitosis.git $ cd gitosis $ sudo python setup.py install @@ -738,7 +738,7 @@ GitHub is also a commercial company that charges for accounts that maintain priv ### Setting Up a User Account ### -The first thing you need to do is set up a free user account. If you visit the Pricing and Signup page at `http://github.com/plans` and click the "Sign Up" button on the Free account (see figure 4-2), you’re taken to the signup page. +The first thing you need to do is set up a free user account. If you visit the "Plans and pricing" page at `https://github.com/pricing` and click the "Sign Up" button on the Free account (see figure 4-2), you’re taken to the signup page. Insert 18333fig0402.png Figure 4-2. The GitHub plan page. diff --git a/az/06-git-tools/01-chapter6.markdown b/az/06-git-tools/01-chapter6.markdown index 550699d2d..ccf9797c0 100644 --- a/az/06-git-tools/01-chapter6.markdown +++ b/az/06-git-tools/01-chapter6.markdown @@ -59,7 +59,7 @@ A lot of people become concerned at some point that they will, by random happens If you do happen to commit an object that hashes to the same SHA-1 value as a previous object in your repository, Git will see the previous object already in your Git database and assume it was already written. If you try to check out that object again at some point, you’ll always get the data of the first object. -However, you should be aware of how ridiculously unlikely this scenario is. The SHA-1 digest is 20 bytes or 160 bits. The number of randomly hashed objects needed to ensure a 50% probability of a single collision is about 2^80 (the formula for determining collision probability is `p = (n(n-1)/2) * (1/2^160))`. 2^80 is 1.2 x 10^24 or 1 million billion billion. That’s 1,200 times the number of grains of sand on the earth. +However, you should be aware of how ridiculously unlikely this scenario is. The SHA-1 digest is 20 bytes or 160 bits. The number of randomly hashed objects needed to ensure a 50% probability of a single collision is about 2^80 (the formula for determining collision probability is `p = (n(n-1)/2) * (1/2^160)`). 2^80 is 1.2 x 10^24 or 1 million billion billion. That’s 1,200 times the number of grains of sand on the earth. Here’s an example to give you an idea of what it would take to get a SHA-1 collision. If all 6.5 billion humans on Earth were programming, and every second, each one was producing code that was the equivalent of the entire Linux kernel history (1 million Git objects) and pushing it into one enormous Git repository, it would take 5 years until that repository contained enough objects to have a 50% probability of a single SHA-1 object collision. A higher probability exists that every member of your programming team will be attacked and killed by wolves in unrelated incidents on the same night. @@ -440,7 +440,7 @@ Your working directory is clean: $ git status # On branch master - nothing to commit (working directory clean) + nothing to commit, working directory clean At this point, you can easily switch branches and do work elsewhere; your changes are stored on your stack. To see which stashes you’ve stored, you can use `git stash list`: @@ -501,7 +501,7 @@ Again, if you don’t specify a stash, Git assumes the most recent stash: You may want to create an alias and effectively add a `stash-unapply` command to your git. For example: $ git config --global alias.stash-unapply '!git stash show -p | git apply -R' - $ git stash + $ git stash apply $ #... work work work $ git stash-unapply @@ -1095,7 +1095,7 @@ Now you have the root of the Rack project in your `rack_branch` branch and your $ ls README -You want to pull the Rack project into your `master` project as a subdirectory. You can do that in Git with `git read-tree`. You’ll learn more about `read-tree` and its friends in Chapter 9, but for now know that it reads the root tree of one branch into your current staging area and working directory. You just switched back to your `master` branch, and you pull the `rack` branch into the `rack` subdirectory of your `master` branch of your main project: +You want to pull the Rack project into your `master` project as a subdirectory. You can do that in Git with `git read-tree`. You’ll learn more about `read-tree` and its friends in Chapter 9, but for now know that it reads the root tree of one branch into your current staging area and working directory. You just switched back to your `master` branch, and you pull the `rack_branch` branch into the `rack` subdirectory of your `master` branch of your main project: $ git read-tree --prefix=rack/ -u rack_branch diff --git a/az/07-customizing-git/01-chapter7.markdown b/az/07-customizing-git/01-chapter7.markdown index 41f5dd33f..c2bb85fc1 100644 --- a/az/07-customizing-git/01-chapter7.markdown +++ b/az/07-customizing-git/01-chapter7.markdown @@ -142,7 +142,7 @@ If you want to try this out, P4Merge works on all major platforms, so you should You can download P4Merge here: - http://www.perforce.com/perforce/downloads/component.html + http://www.perforce.com/product/components/perforce-visual-merge-and-diff-tools To begin, you’ll set up external wrapper scripts to run your commands. I’ll use the Mac path for the executable; in other systems, it will be where your `p4merge` binary is installed. Set up a merge wrapper script named `extMerge` that calls your binary with all the arguments provided: diff --git a/az/08-git-and-other-scms/01-chapter8.markdown b/az/08-git-and-other-scms/01-chapter8.markdown index 9aaf5c4e9..e21879ba3 100644 --- a/az/08-git-and-other-scms/01-chapter8.markdown +++ b/az/08-git-and-other-scms/01-chapter8.markdown @@ -20,7 +20,7 @@ Don’t rewrite your history and try to push again, and don’t push to a parall ### Setting Up ### -To demonstrate this functionality, you need a typical SVN repository that you have write access to. If you want to copy these examples, you’ll have to make a writeable copy of my test repository. In order to do that easily, you can use a tool called `svnsync` that comes with more recent versions of Subversion — it should be distributed with at least 1.4. For these tests, I created a new Subversion repository on Google code that was a partial copy of the `protobuf` project, which is a tool that encodes structured data for network transmission. +To demonstrate this functionality, you need a typical SVN repository that you have write access to. If you want to copy these examples, you’ll have to make a writeable copy of my test repository. In order to do that easily, you can use a tool called `svnsync` that comes with more recent versions of Subversion — it should be distributed with at least 1.4. For these tests, I created a new Subversion repository on SourceForge that was a partial copy of the `protobuf` project, which is a tool that encodes structured data for network transmission. To follow along, you first need to create a new local Subversion repository: @@ -602,7 +602,7 @@ The last thing you need to do is to return the current mark so it can be passed return mark -NOTE: If you are running on Windows you'll need to make sure that you add one extra step. As metioned before, Windows uses CRLF for new line characters while git fast-import expects only LF. To get around this problem and make git fast-import happy, you need to tell ruby to use LF instead of CRLF: +NOTE: If you are running on Windows you'll need to make sure that you add one extra step. As mentioned before, Windows uses CRLF for new line characters while git fast-import expects only LF. To get around this problem and make git fast-import happy, you need to tell ruby to use LF instead of CRLF: $stdout.binmode diff --git a/be/01-introduction/01-chapter1.markdown b/be/01-introduction/01-chapter1.markdown index 93b2bc5ee..604f912e2 100644 --- a/be/01-introduction/01-chapter1.markdown +++ b/be/01-introduction/01-chapter1.markdown @@ -161,9 +161,9 @@ Insert 18333fig0106.png ### Усталёўка на Mac ### -Ёсць два лёгкіх пуці ўсталёкі Git на Mac. Самы лёгкі - выкарыстаць графічны ўсталёўшчык, які вы можаце спампаваць са старонкі Google Code(гл. Малюнак 1-7): +Ёсць два лёгкіх пуці ўсталёкі Git на Mac. Самы лёгкі - выкарыстаць графічны ўсталёўшчык, які вы можаце спампаваць са старонкі SourceForge(гл. Малюнак 1-7): - http://code.google.com/p/git-osx-installer + http://sourceforge.net/projects/git-osx-installer/ Insert 18333fig0107.png Малюнак 1-7. Усталёўчшык Git на OS X. diff --git a/be/02-git-basics/01-chapter2.markdown b/be/02-git-basics/01-chapter2.markdown index 4767c095a..d1f61ded5 100644 --- a/be/02-git-basics/01-chapter2.markdown +++ b/be/02-git-basics/01-chapter2.markdown @@ -55,7 +55,7 @@ Insert 18333fig0201.png $ git status # On branch master - nothing to commit (working directory clean) + nothing to commit, working directory clean Гэта значыць, што ў вас чысты працоўны каталог, іншымі словамі - адсутнічаюць мадыфікаваныя адсочваемыя файлы. Git таксама не знайшоў якія-небудзь неадсочваемыя файлы, у зваротным выпадку яны былі б пералічаны тут. У канцы каманда паказвае вам на якой ветцы вы знаходзіцеся. This means you have a clean working directory — in other words, there are no tracked and modified files. Git also doesn’t see any untracked files, or they would be listed here. Finally, the command tells you which branch you’re on. For now, that is always `master`, which is the default; you won’t worry about it here. The next chapter will go over branches and references in detail. diff --git a/ca/01-introduction/01-chapter1.markdown b/ca/01-introduction/01-chapter1.markdown index 726af3fb5..1944283d7 100644 --- a/ca/01-introduction/01-chapter1.markdown +++ b/ca/01-introduction/01-chapter1.markdown @@ -4,11 +4,11 @@ Aquest capítol tracta com iniciar-se amb Git. Començarem explicant alguns conc ## Control de Versions ## -What is version control, and why should you care? Version control is a system that records changes to a file or set of files over time so that you can recall specific versions later. For the examples in this book you will use software source code as the files being version controlled, though in reality you can do this with nearly any type of file on a computer. +Que es el control de version i per què t'hauria d'importar? El control de versions es un sitema que registra els canvis a un arxiu o conjunt d'arxius de manera que despres pot recuperar cualsevol de les versions. Tot i que els exemples de control de versions del llibre son codi font, potfer servir gairebe quansevol mena de arxiu per del teu ordinador. -If you are a graphic or web designer and want to keep every version of an image or layout (which you would most certainly want to), a Version Control System (VCS) is a very wise thing to use. It allows you to revert files back to a previous state, revert the entire project back to a previous state, compare changes over time, see who last modified something that might be causing a problem, who introduced an issue and when, and more. Using a VCS also generally means that if you screw things up or lose files, you can easily recover. In addition, you get all this for very little overhead. +Si ets un disenyador gràfic o de pagines web i vols guardar cada escuna de les versions d'una imatge o disenys (que segur que vols) un sitema de control de versions (Version Control System -VCS-) sera una eina acurada. Et permetrà torna al estat anterior dels fitxers, tornar a un punt anterior de tot el projecte, comparà canvis en el proces, saber qui es el darrer a modificat coses que potser estant donant problemes, qui a introduit un tema i quant, i encara més coses. Fer servir VCS vol dir que si la pífias o pot arreglar, generalment. i tot aixo amb pocs costos. -### Local Version Control Systems ### +### Sitemas de control de versions locals ### Many people’s version-control method of choice is to copy files into another directory (perhaps a time-stamped directory, if they’re clever). This approach is very common because it is so simple, but it is also incredibly error prone. It is easy to forget which directory you’re in and accidentally write to the wrong file or copy over files you don’t mean to. @@ -161,9 +161,9 @@ Or if you’re on a Debian-based distribution like Ubuntu, try apt-get: ### Installing on Mac ### -There are two easy ways to install Git on a Mac. The easiest is to use the graphical Git installer, which you can download from the Google Code page (see Figure 1-7): +There are two easy ways to install Git on a Mac. The easiest is to use the graphical Git installer, which you can download from the SourceForge page (see Figure 1-7): - http://code.google.com/p/git-osx-installer + http://sourceforge.net/projects/git-osx-installer/ Insert 18333fig0107.png Figure 1-7. Git OS X installer. diff --git a/cs/01-introduction/01-chapter1.markdown b/cs/01-introduction/01-chapter1.markdown index 44fdd2521..6a29be757 100644 --- a/cs/01-introduction/01-chapter1.markdown +++ b/cs/01-introduction/01-chapter1.markdown @@ -6,7 +6,7 @@ Tato kapitola vám ve stručnosti představí systém Git. Začneme od samého z Co je to správa verzí a proč by vás měla zajímat? Správa verzí je systém, který zaznamenává změny souboru nebo sady souborů v průběhu času, a uživatel tak může kdykoli obnovit jeho/jejich konkrétní verzi (tzv. verzování). Příklady verzovaných souborů jsou v této knize ilustrovány na zdrojovém kódu softwaru, avšak ve skutečnosti lze verzování provádět téměř se všemi typy souborů v počítači. -Pokud jste grafik nebo webdesigner a chcete uchovávat všechny verze obrázku nebo všechna rozložení stránky (což jistě není k zahození), je pro vás systém správy verzí (zkráceně VCS z angl. Version Control System) ideálním nástrojem. VCS umožňuje vrátit jednotlivé soubory nebo celý projekt do předchozího stavu, porovnávat změny provedené v průběhu času, zjistit, kdo naposledy upravil něco, co nyní možná způsobuje problémy, kdo vložil jakou verzi a kdy a mnoho dalšího. Používáte-li verzovací systém, většinou to také znamená, že snadno obnovíte soubory, které jste ztratili nebo v nichž byly provedeny nežádoucí změny. Všechny funkcionality verzovacího systému můžete navíc používat velice jednoduchým způsobem. +Pokud jste grafik nebo webdesigner a chcete uchovávat všechny verze obrázku nebo všechna rozložení stránky (což jistě není k zahození), je pro vás systém správy verzí (zkráceně VCS z anglického Version Control System) ideálním nástrojem. VCS umožňuje vrátit jednotlivé soubory nebo celý projekt do předchozího stavu, porovnávat změny provedené v průběhu času, zjistit, kdo naposledy upravil něco, co nyní možná způsobuje problémy, kdo vložil jakou verzi a kdy a mnoho dalšího. Používáte-li verzovací systém, většinou to také znamená, že snadno obnovíte soubory, které jste ztratili nebo v nichž byly provedeny nežádoucí změny. Všechny funkcionality verzovacího systému můžete navíc používat velice jednoduchým způsobem. ### Lokální systémy správy verzí ### @@ -32,16 +32,16 @@ Avšak i tato koncepce má závažné nedostatky. Tímto nejkřiklavějším je ### Distribuované systémy správy verzí ### -V tomto místě přicházejí ke slovu tzv. distribuované systémy správy verzí (DVCS z angl. Distributed Version Control System). V systémech DVCS (např. Git, Mercurial, Bazaar nebo Darcs) uživatelé pouze nestahují nejnovější verzi souborů (tzv. snímek, anglicky snapshot), ale uchovávají kompletní kopii repozitáře (repository). Pokud v takové situaci dojde ke kolapsu serveru, lze jej obnovit zkopírováním repozitáře od libovolného uživatele. Každá lokální kopie (checkout) je plnohodnotnou zálohou všech dat (viz obrázek 1-3). +V tomto místě přicházejí ke slovu tzv. distribuované systémy správy verzí (DVCS z angl. Distributed Version Control System). V systémech DVCS (např. Git, Mercurial, Bazaar nebo Darcs) uživatelé nestahují pouze nejnovější verzi souborů (tzv. snímek, anglicky snapshot), ale uchovávají kompletní kopii repozitáře (repository). Pokud v takové situaci dojde ke kolapsu serveru, lze jej obnovit zkopírováním repozitáře od libovolného uživatele. Každá lokální kopie (checkout) je plnohodnotnou zálohou všech dat (viz obrázek 1-3). Insert 18333fig0103.png Obrázek 1-3. Diagram distribuované správy verzí -Mnoho z těchto systémů navíc bez větších obtíží pracuje i s několika vzdálenými repozitáři, a vy tak můžete v rámci jednoho projektu spolupracovat na různých úrovních s rozdílnými skupinami lidí. Díky tomu si můžete vytvořit několik typů pracovních postupů, což není v centralizovaných systémech (např. v hierarchických modelech) možné. +Mnoho z těchto systémů navíc bez větších obtíží pracuje i s několika vzdálenými repozitáři, takže můžete v rámci jednoho projektu různým způsobem spolupracovat s různými skupinami lidí najednou. Můžete zavést několik typů pracovních postupů, které nejsou v centralizovaných systémech možné — jako jsou například hierarchické modely. ## Stručná historie systému Git ## -Tak jako mnoho velkých věcí v lidské historii se i systém Git zrodil z kreativní destrukce a vášnivého sporu. Jádro Linuxu je software s otevřeným kódem a širokou škálou využití. V letech 1991 — 2002 bylo jádro Linuxu spravováno formou záplat a archivních souborů. V roce 2002 začal projekt vývoje linuxového jádra využívat komerční systém DVCS s názvem Bit-Keeper. +Tak jako mnoho velkých věcí v lidské historii se i systém Git zrodil z kreativní destrukce a vášnivého sporu. Jádro Linuxu je software celkem velkého rozsahu, s otevřeným kódem. V letech 1991 — 2002 bylo jádro Linuxu spravováno formou záplat a archivních souborů. V roce 2002 začal projekt vývoje linuxového jádra využívat komerční systém DVCS s názvem BitKeeper. V roce 2005 se zhoršily vztahy mezi komunitou, která vyvíjela jádro Linuxu, a komerční společností, která vyvinula BitKeeper, a společnost přestala tento systém poskytovat zdarma. To přimělo komunitu vývojářů Linuxu (a zejména Linuse Torvaldse, tvůrce Linuxu), aby vyvinula vlastní nástroj, založený na poznatcích, které nasbírala při užívání systému BitKeeper. Mezi požadované vlastnosti systému patřily zejména: @@ -55,7 +55,7 @@ Od svého vzniku v roce 2005 se Git vyvinul a vyzrál v snadno použitelný syst ## Základy systému Git ## -Jak bychom tedy mohli Git charakterizovat? Odpověď na tuto otázku je velmi důležitá, protože pokud pochopíte, co je Git a na jakém principu pracuje, budete ho bezpochyby moci používat mnohem efektivněji. Při seznámení se systémem Git se pokuste zapomenout na vše, co už možná víte o jiných systémech VCS, např. Subversion nebo Perforce. Vyhnete se tak nežádoucím vlivům, které by vás mohly při používání systému Git mást. Ačkoli je uživatelské rozhraní velmi podobné, Git ukládá a zpracovává informace poněkud odlišně od ostatních systémů. Pochopení těchto rozdílů vám pomůže předejít nejasnostem, které mohou vzniknout při používání systému Git. +Jak bychom tedy mohli Git charakterizovat? Odpověď na tuto otázku je velmi důležitá, protože pokud pochopíte, co je Git a na jakém principu pracuje, budete ho bezpochyby moci používat mnohem efektivněji. Při seznámení se systémem Git se pokuste zapomenout na vše, co už možná víte o jiných systémech VCS, např. Subversion nebo Perforce. Vyhnete se tak nežádoucím vlivům, které by vás mohly při používání systému Git mást. Ačkoli je uživatelské rozhraní velmi podobné, Git ukládá a zpracovává informace poněkud odlišně od ostatních systémů. Pochopení těchto rozdílů vám pomůže předejít nejasnostem, které mohou při používání systému Git vzniknout. ### Snímky, nikoli rozdíly ### @@ -69,31 +69,31 @@ Git zpracovává data jinak. Chápe je spíše jako sadu snímků (snapshots) vl Insert 18333fig0105.png Obrázek 1-5. Git ukládá data jako snímky projektu proměnlivé v čase. -Toto je důležitý rozdíl mezi systémem Git a téměř všemi ostatními systémy VCS. Git díky tomu znovu zkoumá skoro každý aspekt správy verzí, které ostatní systémy kopírovaly z předchozí generace. Git je tak z obyčejného VCS spíše povýšen na vlastní systém správy souborů s řadou skutečně výkonných nástrojů, jež stojí na jeho vrcholu. Některé přednosti, které tato metoda správy dat nabízí, si podrobně ukážeme na systému větvení v kapitole 3. +Toto je důležitý rozdíl mezi systémem Git a téměř všemi ostatními systémy VCS. Git díky tomu znovu zkoumá skoro každý aspekt správy verzí, které ostatní systémy kopírovaly z předchozí generace. Git se podobá malému systému souborů (spíše než obyčejnému VCS) s řadou skutečně výkonných nástrojů, jež jsou na něm postavené. Některé přednosti, které tato metoda správy dat nabízí, si podrobně ukážeme na systému větvení v kapitole 3. ### Téměř každá operace je lokální ### Většina operací v systému Git vyžaduje ke své činnosti pouze lokální soubory a zdroje a nejsou potřeba informace z jiných počítačů v síti. Pokud jste zvyklí pracovat se systémy CVCS, kde je většina operací poznamenána latencí sítě, patrně vás při práci v systému Git napadne, že mu bohové rychlosti dali do vínku nadpřirozené schopnosti. Protože máte celou historii projektu uloženou přímo na svém lokálním disku, probíhá většina operací takřka okamžitě. -Pokud chcete například procházet historii projektu, Git kvůli tomu nemusí vyhledávat informace na serveru — načte ji jednoduše přímo z vaší lokální databáze. Znamená to, že se historie projektu zobrazí téměř neprodleně. Pokud si chcete prohlédnout změny provedené mezi aktuální verzí souboru a týmž souborem před měsícem, Git vyhledá měsíc starý soubor a provede lokální výpočet rozdílů, aniž by o to musel žádat vzdálený server nebo stahovat starší verzi souboru ze vzdáleného serveru a poté provádět lokální výpočet. +Pokud chcete například procházet historii projektu, Git kvůli tomu nemusí vyhledávat informace na serveru — načte je jednoduše přímo z vaší lokální databáze. Znamená to, že se historie projektu zobrazí téměř hned. Pokud si chcete prohlédnout změny provedené mezi aktuální verzí souboru a týmž souborem před měsícem, Git vyhledá měsíc starý soubor a provede lokální výpočet rozdílů, aniž by o to musel žádat vzdálený server nebo stahovat starší verzi souboru ze vzdáleného serveru a poté provádět lokální výpočet. -To také znamená, že je jen velmi málo operací, které nemůžete provádět offline nebo bez připojení k VPN. Jste-li v letadle nebo ve vlaku a chcete pokračovat v práci, můžete beze všeho zapisovat nové revize. Ty se odešlou ve chvíli, kdy se opět připojíte k síti. Jestliže přijedete domů a zjistíte, že VPN klient nefunguje, stále můžete pracovat. V mnoha jiných systémech je takový postup nemožný nebo přinejmenším obtížný. Například v systému Perforce toho lze bez připojení k serveru dělat jen velmi málo, v systémech Subversion a CVS můžete sice upravovat soubory, ale nemůžete zapisovat změny do databáze, neboť ta je offline. Možná to vypadá jako maličkost, ale divili byste se, jaký je to velký rozdíl. +To také znamená, že je jen velmi málo operací, které nemůžete provádět offline nebo bez připojení k VPN. Jste-li v letadle nebo ve vlaku a chcete pokračovat v práci, můžete beze všeho zapisovat nové revize. Ty odešlete až po opětovném připojení k síti. Jestliže přijedete domů a zjistíte, že VPN klient nefunguje, stále můžete pracovat. V mnoha jiných systémech je takový postup nemožný nebo přinejmenším obtížný. Například v systému Perforce toho lze bez připojení k serveru dělat jen velmi málo, v systémech Subversion a CVS můžete sice upravovat soubory, ale nemůžete zapisovat změny do databáze, neboť ta je offline. Možná to vypadá jako maličkost, ale divili byste se, jak velký je v tom rozdíl. ### Git pracuje důsledně ### -Než je v systému Git cokoli uloženo, je nejprve proveden kontrolní součet, který je potom používán k identifikaci uloženého souboru. Znamená to, že není možné změnit obsah jakéhokoli souboru nebo adresáře, aniž by o tom Git nevěděl. Tato funkce je integrována do systému Git na nejnižších úrovních a je v souladu s jeho filozofií. Nemůže tak dojít ke ztrátě informací při přenosu dat nebo k poškození souboru, aniž by to byl Git schopen zjistit. +Než je v systému Git cokoli uloženo, je nejprve proveden kontrolní součet, který je potom používán k identifikaci uloženého souboru. Znamená to, že není možné změnit obsah jakéhokoli souboru nebo adresáře, aniž by o tom Git nevěděl. Tato funkce je integrována do systému Git na nejnižších úrovních a je nedílnou součástí jeho filozofie. Nemůže tak dojít ke ztrátě informací při přenosu dat nebo k poškození souboru, aniž by to byl Git schopen zjistit. Mechanismus, který Git k tomuto kontrolnímu součtu používá, se nazývá otisk SHA-1 (SHA-1 hash). Jedná se o řetězec o 40 hexadecimálních znacích (0–9; a–f) vypočítaný na základě obsahu souboru nebo adresářové struktury systému Git. Otisk SHA-1 může vypadat například takto: 24b9da6552252987aa493b52f8696cd6d3b00373 -S těmito otisky se budete setkávat ve všech úložištích systému Git, protože je používá opravdu často. Neukládá totiž soubory podle jejich názvu, ale ve své databázi podle otisku (hashe) jeho obsahu. +S těmito otisky se budete setkávat ve všech úložištích systému Git, protože je používá opravdu často. Git nic neukládá podle názvu souboru. Místo toho používá databázi adresovatelnou hodnotou otisku, který odpovídá obsahu souboru. ### Git většinou jen přidává data ### Jednotlivé operace ve většině případů jednoduše přidávají data do Git databáze. Přimět systém, aby udělal něco, co nelze vzít zpět, nebo aby smazal jakákoli data, je velice obtížné. Stejně jako ve všech systémech VCS můžete ztratit nebo nevratně zničit změny, které ještě nebyly zapsány. Jakmile však jednou zapíšete snímek do systému Git, je téměř nemožné ho ztratit, zvlášť pokud pravidelně zálohujete databázi do jiného repozitáře. -Díky tomu vás bude práce se systémem Git bavit. Budete pracovat s vědomím, že můžete experimentovat, a neriskujete přitom nevratné zničení své práce. Podrobnější informace o tom, jak Git ukládá data a jak lze obnovit zdánlivě ztracenou práci, najdete v kapitole 9 „Git pod pokličkou“. +Díky tomu vás bude práce se systémem Git bavit. Budete pracovat s vědomím, že můžete experimentovat, a neriskujete přitom nevratné zničení své práce. Podrobnější informace o tom, jak Git ukládá data a jak lze obnovit zdánlivě ztracenou práci, najdete v kapitole 9. ### Tři stavy ### @@ -104,9 +104,9 @@ Z toho vyplývá, že projekt je v systému Git rozdělen do tří hlavních č Insert 18333fig0106.png Obrázek 1-6. Pracovní adresář, oblast připravených změn a adresář Git -V adresáři Git ukládá systém databázi metadat a objektů k projektu. Je to nejdůležitější část systému Git a zároveň adresář, který se zkopíruje, když klonujete repozitář z jiného počítače. +Adresář Git (repozitář) je místo, kde Git uchovává metadata a databázi objektů vašeho projektu. Je to nejdůležitější část systému Git a zároveň adresář, který se zkopíruje, když klonujete repozitář z jiného počítače. -Pracovní adresář obsahuje lokální kopii jedné verze projektu. Tyto soubory jsou staženy ze zkomprimované databáze v adresáři Git a umístěny na disk, abyste je mohli upravovat. +Pracovní adresář obsahuje lokální kopii jedné verze projektu. Tyto soubory jsou staženy ze zkomprimované databáze v adresáři Git a umístěny na disk, kde je můžete používat nebo upravovat. Oblast připravených změn je jednoduchý soubor, většinou uložený v adresáři Git, který obsahuje informace o tom, co bude obsahovat příští revize. Soubor se někdy označuje také anglickým výrazem „index“, ale oblast připravených změn (staging area) je už dnes termín běžnější. @@ -120,13 +120,13 @@ Nachází-li se konkrétní verze souboru v adresáři Git, je považována za z ## Instalace systému Git ## -Je načase začít systém Git aktivně používat. Instalaci můžete provést celou řadou způsobů — obvyklá je instalace ze zdrojových souborů nebo instalace existujícího balíčku, určeného pro vaši platformu. +Je načase začít systém Git aktivně používat. Instalaci můžete provést celou řadou způsobů. Většinou se využívá buď instalace ze zdrojových souborů, nebo instalace z existujícího balíčku, určeného pro vaši platformu. ### Instalace ze zdrojových souborů ### -Pokud je to možné, je nejvhodnější instalovat Git ze zdrojových souborů. Tak je zaručeno, že vždy získáte aktuální verzi. Každá další verze systému se snaží přidat nová vylepšení uživatelského rozhraní. Použití poslední verze je tedy zpravidla tou nejlepší cestou, samozřejmě pokud vám nedělá problémy kompilace softwaru ze zdrojových souborů. +Pokud je to možné, je nejvhodnější instalovat Git ze zdrojových souborů. Tak je zaručeno, že vždy získáte aktuální verzi. Každá další verze systému se snaží přidat nová vylepšení uživatelského rozhraní. Použití poslední verze je tedy zpravidla tou nejlepší cestou, samozřejmě pokud vám nedělá problémy kompilace softwaru ze zdrojových souborů. Skutečností také je, že mnoho linuxových distribucí obsahuje velmi staré balíčky. Takže pokud nepoužíváte velmi čerstvou distribuci, nebo pokud záměrně používáte starší verzi, bývá instalace ze zdrojových souborů nejlepší volbou. -Před instalcí samotného Gitu musí váš systém obsahovat následující knihovny, na nichž je Git závislý: curl, zlib, openssl, expat, a libiconv. Pokud používáte yum (např. Fedora) nebo apt-get (např. distribuce založené na Debianu), můžete k instalaci použít jeden z následujících příkazů: +Před instalací samotného Gitu musí váš systém obsahovat následující knihovny, na nichž je Git závislý: curl, zlib, openssl, expat, a libiconv. Pokud používáte systém s nástrojem yum (například u distribuce Fedora) nebo apt-get (například distribuce odvozené od Debianu), můžete k instalaci použít jeden z následujících příkazů: $ yum install curl-devel expat-devel gettext-devel \ openssl-devel zlib-devel @@ -138,7 +138,7 @@ Po doinstalování všech potřebných závislostí můžete pokračovat stažen http://git-scm.com/download -Poté přistupte ke kompilaci a instalaci: +Poté spusťte kompilaci a instalaci: $ tar -zxf git-1.7.2.2.tar.gz $ cd git-1.7.2.2 @@ -151,26 +151,26 @@ Po dokončení instalace můžete rovněž vyhledat aktualizace systému Git pro ### Instalace v Linuxu ### -Chcete-li nainstalovat Git v Linuxu pomocí binárního instalátoru, většinou tak můžete učinit pomocí základního nástroje pro správu balíčků, který byl součástí vaší distribuce. Ve Fedoře můžete použít nástroj yum: +Chcete-li nainstalovat Git v Linuxu pomocí binárního instalátoru, většinou tak můžete učinit pomocí základního nástroje pro správu balíčků, který je součástí vaší distribuce. Ve Fedoře můžete použít nástroj yum: - $ yum install git-core + $ yum install git -V distribuci založené na Debianu (např. Ubuntu) zkuste použít program apt-get: +V distribuci založené na Debianu (jako je například Ubuntu) zkuste použít program apt-get: $ apt-get install git ### Instalace v systému Mac ### -Existují dva jednoduché způsoby, jak nainstalovat Git v systému Mac. Tím nejjednodušším je použít grafický instalátor Git, který si můžete stáhnout ze stránky Google Code (viz obrázek 1-7): +Existují dva jednoduché způsoby, jak nainstalovat Git v systému Mac. Tím nejjednodušším je použít grafický instalátor Git, který si můžete stáhnout ze stránky SourceForge (viz obrázek 1-7): - http://code.google.com/p/git-osx-installer + http://sourceforge.net/projects/git-osx-installer/ Insert 18333fig0107.png Obrázek 1-7. Instalátor Git pro OS X Jiným obvyklým způsobem je instalace systému Git prostřednictvím systému MacPorts (`http://www.macports.org`). Máte-li systém MacPorts nainstalován, nainstalujte Git příkazem: - $ sudo port install git-core +svn +doc +bash_completion +gitweb + $ sudo port install git +svn +doc +bash_completion +gitweb Není nutné přidávat všechny doplňky, ale pokud budete někdy používat Git s repozitáři systému Subversion, budete pravděpodobně chtít nainstalovat i doplněk +svn (viz kapitola 8). @@ -178,7 +178,7 @@ Není nutné přidávat všechny doplňky, ale pokud budete někdy používat Gi Instalace systému Git v OS Windows je velice nenáročná. Postup instalace projektu msysGit patří k těm nejjednodušším. Ze stránky GitHub stáhněte instalační soubor exe a spusťte ho: - http://msysgit.github.com/ + http://msysgit.github.io Po dokončení instalace budete mít k dispozici jak verzi pro příkazový řádek (včetně SSH klienta, který se vám bude hodit později), tak standardní grafické uživatelské rozhraní. @@ -188,40 +188,40 @@ Poznámka k používání pod Windows: Git byste měli používat z dodaného sh Nyní, když máte Git nainstalovaný, můžete provést některá uživatelská nastavení systému. Nastavení stačí provést pouze jednou — zůstanou zachována i po případných aktualizacích. -Nastavení konfiguračních proměnných systému, které ovlivňují jak vzhled systému Git, tak ostatní aspekty jeho práce, umožňuje příkaz git config. Tyto proměnné mohou být uloženy na třech různých místech: +Nastavení konfiguračních proměnných systému, které ovlivňují jak vzhled systému Git, tak ostatní aspekty jeho práce, umožňuje příkaz `git config`. Tyto proměnné mohou být uloženy na třech různých místech: -* Soubor `/etc/gitconfig` obsahuje údaje o všech uživatelích systému a jejich repozitářích. Pokud příkazu `git config` zadáme parametr `--system` bude číst a zapisovat jen do tohoto souboru. +* Soubor `/etc/gitconfig` obsahuje údaje pro všechny uživatele systému a pro všechny jejich repozitáře. Pokud příkazu `git config` zadáme parametr `--system` bude číst a zapisovat jen do tohoto souboru. * Soubor `~/.gitconfig` je vázán na uživatelský účet. Čtení a zápis do tohoto souboru zajistíte zadáním parametru `--global`. -* Konfigurační soubor v adresáři Git (tedy `.git/config`) jakéhokoliv užívaného repozitáře přísluší tomuto konkrétnímu repozitáři. Každá úroveň je nadřazená hodnotám úrovně předchozí, takže hodnoty v `.git/config` přebíjejí hodnotami v `/etc/gitconfig`. +* Konfigurační soubor v adresáři Git (tedy `.git/config`) jakéhokoliv užívaného repozitáře přísluší tomuto konkrétnímu repozitáři. Každá úroveň je nadřazená hodnotám úrovně předchozí, takže hodnoty v `.git/config` převládnou nad hodnotami v `/etc/gitconfig`. -Ve Windows používá Git soubor `.gitconfig`, který je umístěný v adresáři `$HOME` (v prostředí Windows je to `%USERPROFILE%`), což je u většiny uživatelů `C:\Documents and Settings\$USER` nebo `C:\Users\$USER` (kde `$USER` se v prostředí Windows označuje `%USERNAME%`). I ve Windows se hledá soubor `/etc/gitconfig`, který je ale umístěn relativně v kořeni Msys, tedy vůči místu, do kterého jste se po spuštění instalačního programu rozhodli Git nainstalovat. +Ve Windows Git hledá soubor `.gitconfig` v adresáři `$HOME` (v proměnných prostředí Windows je to `%USERPROFILE%`), což je u většiny uživatelů `C:\Documents and Settings\$USER` nebo `C:\Users\$USER` (`$USER` se ve Windows zapisuje odkazem na proměnnou prostředí `%USERNAME%`). I ve Windows se hledá soubor `/etc/gitconfig`, který je ale umístěn relativně v kořeni MSys, tedy vůči místu, do kterého jste se po spuštění instalačního programu rozhodli Git nainstalovat. -### Totožnost uživatele ### +### Vaše totožnost ### -První věcí, kterou byste měli po nainstalování systému Git udělat, je nastavení uživatelského jména (user name) a e-mailové adresy. Tyto údaje se totiž později využívají při všech revizích v systému Git a jsou nezměnitelnou složkou každé revize, kterou zapíšete: +První věcí, kterou byste měli po nainstalování systému Git udělat, je nastavení vašeho uživatelského jména (user name) a e-mailové adresy. Je to důležité, protože tuto informaci Git používá pro každý zápis revize a uvedené údaje stanou trvalou složkou záznamů o revizi, které budou putovat po okolí: $ git config --global user.name "John Doe" $ git config --global user.email johndoe@example.com -Použijete-li parametr `--global`, pak také toto nastavení stačí provést pouze jednou. Git bude používat tyto údaje pro všechny operace, které v systému uděláte. Pokud chcete pro konkrétní projekty změnit uživatelské jméno nebo e-mailovou adresu, můžete příkaz spustit bez parametru `--global`. V takovém případě je nutné, abyste se nacházeli v adresáři daného projektu. +Použijete-li parametr `--global`, pak také toto nastavení stačí provést pouze jednou. Git bude používat tyto údaje pro všechny operace, které v systému uděláte. Pokud chcete pro konkrétní projekt uživatelské jméno nebo e-mailovou adresu změnit (přebít), můžete příkaz spustit bez parametru `--global`. V takovém případě je nutné, abyste se nacházeli v adresáři daného projektu. -### Nastavení editoru ### +### Váš editor ### -Nyní, když jste zadali své osobní údaje, můžete nastavit výchozí textový editor, který bude Git využívat pro psaní zpráv. Pokud toto nastavení nezměníte, bude Git používat výchozí editor vašeho systému, jímž je většinou Vi nebo Vim. Chcete-li používat jiný textový editor (např. Emacs), můžete použít následující příkaz: +Nyní, když jste zadali své osobní údaje, můžete nastavit výchozí textový editor, který se použije, když po vás Git bude chtít napsat nějakou zprávu. Pokud toto nastavení nezměníte, bude Git používat výchozí editor vašeho systému, jímž je většinou Vi nebo Vim. Chcete-li používat jiný textový editor, například Emacs, můžete použít následující příkaz: $ git config --global core.editor emacs -### Nastavení nástroje diff ### +### Váš nástroj diff ### -Další proměnnou, jejíž nastavení můžete považovat za užitečné, je výchozí nástroj diff, jenž bude Git používat k řešení konfliktů při slučování. Řekněme, že jste se rozhodli používat vimdiff: +Další užitečnou volbou, jejíž nastavení můžete chtít upravit, je výchozí nástroj pro zjišťování rozdílů (diff), který Git používá k řešení konfliktů při slučování (merge). Řekněme, že jste se rozhodli používat vimdiff: $ git config --global merge.tool vimdiff Jako platné nástroje slučování Git akceptuje: kdiff3, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, ecmerge a opendiff. Nastavit můžete ale i jiné uživatelské nástroje — více informací o této možnosti naleznete v kapitole 7. -### Kontrola provedeného nastavení ### +### Kontrola vašeho nastavení ### -Chcete-li zkontrolovat provedené nastavení, použijte příkaz `git config --list`. Git vypíše všechna aktuálně dostupná nastavení: +Chcete-li zkontrolovat vaše nastavení, použijte příkaz `git config --list`. Git vypíše všechna aktuálně dostupná nastavení: $ git config --list user.name=Scott Chacon @@ -232,14 +232,14 @@ Chcete-li zkontrolovat provedené nastavení, použijte příkaz `git config --l color.diff=auto ... -Některé klíče se mohou objevit vícekrát, protože Git načítá stejný klíč z různých souborů (např. `/etc/gitconfig` a `~/.gitconfig`). V takovém případě použije Git poslední hodnotu pro každý unikátní klíč, který vidí. +Některé klíče se mohou objevit vícekrát, protože Git načítá stejný klíč z různých souborů (například `/etc/gitconfig` a `~/.gitconfig`). V takovém případě použije Git poslední hodnotu pro každý unikátní klíč, který vidí. -Můžete také zkontrolovat, jakou hodnotu Git uchovává pro konkrétní položku. Zadejte příkaz `git config {key}`: +Můžete také zkontrolovat, jakou hodnotu Git uchovává pro konkrétní klíč zadáním `git config {klíč}`: $ git config user.name Scott Chacon -## Kde hledat pomoc ## +## Získání nápovědy ## Budete-li někdy při používání systému Git potřebovat pomoc, existují tři způsoby, jak vyvolat nápovědu z manuálové stránky (manpage) pro jakýkoli z příkazů systému Git: @@ -247,12 +247,12 @@ Budete-li někdy při používání systému Git potřebovat pomoc, existují t $ git --help $ man git- -Například manpage nápovědu pro příkaz config vyvoláte zadáním: +Například manpage nápovědu pro příkaz `config` vyvoláte zadáním: $ git help config Tyto příkazy jsou užitečné, neboť je můžete spustit kdykoli, dokonce i offline. -Pokud nenajdete pomoc na manuálové stránce ani v této knize a uvítali byste osobní pomoc, můžete zkusit kanál `#git` nebo `#github` na serveru Freenode IRC (irc.freenode.net). Na těchto kanálech se většinou pohybují stovky lidí, kteří mají se systémem Git bohaté zkušenosti a často ochotně pomohou. +Pokud nestačí ani manuálová stránka ani tato kniha a uvítali byste osobní pomoc, můžete zkusit kanál `#git` nebo `#github` na serveru Freenode IRC (irc.freenode.net). Na těchto kanálech se většinou pohybují stovky lidí, kteří mají se systémem Git bohaté zkušenosti a často ochotně pomohou. (Nutno ovšem podotknout, že se na těchto kanálech mluví anglicky – pozn. překl.) ## Shrnutí ## diff --git a/cs/02-git-basics/01-chapter2.markdown b/cs/02-git-basics/01-chapter2.markdown index 82ffcc030..c301bbb54 100644 --- a/cs/02-git-basics/01-chapter2.markdown +++ b/cs/02-git-basics/01-chapter2.markdown @@ -1,10 +1,10 @@ # Základy práce se systémem Git # -Pokud jste ochotni přečíst si o systému Git jen jednu kapitolu, měla by to být právě tahle. Tato kapitola popíše všechny základní příkazy, jejichž prováděním strávíte drtivou většinu času při práci se systémem Git. Po přečtení kapitoly byste měli být schopni nakonfigurovat a inicializovat repozitář, spustit a ukončit sledování souborů, připravovat soubory a zapisovat revize. Ukážeme také, jak nastavit Git, aby ignoroval určité soubory a masky souborů, jak rychle a jednoduše vrátit nežádoucí změny, jak procházet historii projektu a zobrazit změny mezi jednotlivými revizemi a jak posílat soubory do vzdálených repozitářů a stahovat z nich. +Pokud jste ochotni přečíst si o systému Git jen jednu kapitolu, měla by to být právě tahle. Tato kapitola popíše všechny základní příkazy, jejichž prováděním strávíte při práci se systémem Git drtivou většinu času. Po přečtení kapitoly byste měli být schopni nakonfigurovat a inicializovat repozitář, spustit a ukončit sledování souborů, připravovat soubory a zapisovat revize. Ukážeme si také, jak nastavit Git, aby ignoroval určité soubory a masky souborů, jak rychle a jednoduše vrátit nežádoucí změny, jak procházet historii projektu a zobrazit změny mezi jednotlivými revizemi a jak posílat soubory do vzdálených repozitářů a naopak z nich soubory zase stahovat. ## Získání repozitáře Git ## -Projekt v systému Git lze získat dvěma základními způsoby. První vezme existující projekt nebo adresář a importuje ho do systému Git. Druhý naklonuje existující repozitář Git z jiného serveru. +Projekt v systému Git lze získat dvěma základními způsoby. První způsob spočívá v tom, že vezmeme existující projekt nebo adresář a importujeme ho do systému Git. Druhý způsob spočívá v naklonování již existujícího repozitáře Git z jiného serveru. ### Inicializace repozitáře v existujícím adresáři ### @@ -12,9 +12,9 @@ Chcete-li zahájit sledování existujícího projektu v systému Git, přejdět $ git init -Příkaz vytvoří nový podadresář s názvem `.git`, který bude obsahovat všechny soubory nezbytné pro repozitář, tzv. kostru repozitáře Git. V tomto okamžiku ještě není nic z vašeho projektu sledováno. (Více informací o tom, jaké soubory obsahuje právě vytvořený adresář `.git`, naleznete v kapitole 9.) +Příkaz vytvoří nový podadresář s názvem `.git`, který bude obsahovat všechny soubory nezbytné pro repozitář, tzv. kostru repozitáře Git. V tomto okamžiku se z vašeho projektu ještě nic nesleduje. (Více informací o tom, jaké soubory obsahuje právě vytvořený adresář `.git`, naleznete v *kapitole 9*.) -Chcete-li spustit verzování existujících souborů (na rozdíl od prázdného adresáře), měli byste pravděpodobně zahájit sledování (tracking) těchto souborů a provést první revizi (commit). Můžete tak učinit pomocí několika příkazů `git add`, jimiž určíte soubory, které chcete sledovat, a provedete revizi: +Chcete-li spustit verzování existujících souborů (a ne jen prázdného adresáře), měli byste pravděpodobně zahájit sledování (tracking) těchto souborů a provést první revizi (commit). Můžete tak učinit pomocí několika příkazů `git add`, jimiž určíte soubory, které chcete sledovat, a provedete revizi: $ git add *.c $ git add README @@ -24,27 +24,27 @@ K tomu, co přesně tyto příkazy provedou, se dostaneme za okamžik. V této c ### Klonování existujícího repozitáře ### -Chcete-li vytvořit kopii existujícího repozitáře Git (například u projektu, do nějž chcete začít přispívat), pak příkazem, který hledáte, je `git clone`. Pokud jste zvyklí pracovat s jinými systémy VCS, např. se systémem Subversion, jistě jste si všimli, že příkaz zní `clone`, a nikoli `checkout`. Souvisí to s jedním podstatným rozdílem: Git stáhne kopii téměř všech dat na serveru. Po spuštění příkazu `git clone` budou k historii projektu staženy všechny verze všech souborů. Pokud by někdy poté došlo k poruše disku serveru, lze použít libovolný z těchto klonů na kterémkoli klientovi a obnovit pomocí něj server zpět do stavu, v němž byl v okamžiku klonování (může dojít ke ztrátě některých zásuvných modulů na straně serveru apod., ale všechna verzovaná dat budou obnovena – další podrobnosti v kapitole 4). +Chcete-li vytvořit kopii existujícího repozitáře Git (například u projektu, do nějž chcete začít přispívat), pak příkazem, který hledáte, je `git clone`. Pokud jste zvyklí pracovat s jinými systémy pro správu verzí, jako je například Subversion, jistě jste si všimli, že příkaz zní `clone`, a nikoli `checkout`. Souvisí to s jedním podstatným rozdílem: Git získá kopii téměř všech dat na serveru. Po spuštění příkazu `git clone` budou k historii projektu staženy všechny verze všech souborů. Pokud by někdy poté došlo k poruše disku serveru, lze použít libovolný z těchto klonů na kterémkoli klientovi a obnovit pomocí něj server zpět do stavu, v němž byl v okamžiku klonování (může dojít ke ztrátě některých zásuvných modulů na straně serveru a podobných věcí, ale všechna verzovaná data budou obnovena. Další podrobnosti naleznete v *kapitole 4*). Repozitář naklonujete příkazem `git clone [url]`. Pokud například chcete naklonovat knihovnu Ruby Git nazvanou Grit, můžete to provést následovně: $ git clone git://github.com/schacon/grit.git -Tímto příkazem vytvoříte adresář s názvem `grit`, inicializujete v něm adresář `.git`, stáhnete všechna data pro tento repozitář a systém rovněž stáhne pracovní kopii nejnovější verze. Přejdete-li do nového adresáře `grit`, uvidíte v něm soubory projektu připravené ke zpracování nebo jinému použití. Pokud chcete naklonovat repozitář do adresáře pojmenovaného jinak než grit, můžete název zadat jako další parametr na příkazovém řádku: +Tímto příkazem se vytvoří adresář s názvem `grit`, inicializuje se v něm adresář `.git`, stáhnou se všechna data pro tento repozitář a vytvoří se pracovní kopie nejnovější verze. Přejdete-li do nového adresáře `grit`, uvidíte v něm soubory projektu připravené ke zpracování nebo jinému použití. Pokud chcete naklonovat repozitář do adresáře pojmenovaného jinak než grit, můžete název zadat jako další parametr na příkazovém řádku: $ git clone git://github.com/schacon/grit.git mygrit -Tento příkaz učiní totéž co příkaz předchozí, jen cílový adresář se bude jmenovat `mygrit`. +Tento příkaz učiní totéž co příkaz předchozí, ale cílový adresář se bude jmenovat `mygrit`. -Git nabízí celou řadu různých přenosových protokolů. Předchozí příklad využívá protokol `git://`, můžete se ale setkat také s protokolem `http(s)://` nebo `user@server:/path.git`, který používá přenosový protokol SSH. V kapitole 4 budou představeny všechny dostupné parametry pro nastavení serveru pro přístup do repozitáře Git, včetně jejich předností a nevýhod. +Git nabízí celou řadu různých přenosových protokolů. Předchozí příklad využívá protokol `git://`, můžete se ale setkat také s protokolem `http(s)://` nebo `user@server:/path.git`, který používá přenosový protokol SSH. V *kapitole 4* budou představeny všechny dostupné možnosti, které mohou být pro přístup do repozitáře Git na serveru nastaveny, včetně jejich předností a nevýhod. ## Nahrávání změn do repozitáře ## -Nyní máte vytvořen repozitář Git a checkout nebo pracovní kopii souborů k projektu. Řekněme, že potřebujete udělat pár změn a zapsat snímky těchto změn do svého repozitáře pokaždé, kdy se projekt dostane do stavu, v němž ho chcete nahrát. +Nyní máte vytvořen opravdový gitový repozitář a pracovní kopii souborů k projektu (checkout). Řekněme, že potřebujete udělat pár změn a zapsat snímky těchto změn do svého repozitáře pokaždé, kdy se projekt dostane do stavu, který chcete zaznamenat. -Nezapomeňte, že každý soubor ve vašem pracovním adresáři může být ve dvou různých stavech: sledován a nesledován. Za sledované jsou označovány soubory, které byly součástí posledního snímku. Mohou být ve stavu změněno (modified), nezměněno (unmodified) nebo připraveno k zapsání (staged). Nesledované soubory jsou všechny ostatní, tedy veškeré soubory ve vašem pracovním adresáři, které nebyly obsaženy ve vašem posledním snímku a nejsou v oblasti připravených změn. Po úvodním klonování repozitáře budou všechny vaše soubory sledované a nezměněné, protože jste právě provedli jejich checkout a dosud jste neudělali žádné změny. +Nezapomeňte, že každý soubor ve vašem pracovním adresáři může být ve dvou různých stavech: *sledován* (tracked) a *nesledován* (untracked). Za *sledované* jsou označovány soubory, které byly součástí posledního snímku. Mohou být ve stavu *změněn* (modified), *nezměněn* (unmodified) nebo *připraven k zapsání* (staged). *Nesledované* soubory jsou všechny ostatní, tedy veškeré soubory ve vašem pracovním adresáři, které nebyly obsaženy ve vašem posledním snímku a nejsou v oblasti připravených změn. Po úvodním klonování repozitáře budou všechny vaše soubory sledované a nezměněné, protože jste právě provedli jejich checkout a dosud jste neudělali žádné změny. -Jakmile začnete soubory upravovat, Git je bude považovat za „změněné“, protože jste v nich od poslední revize provedli změny. Poté všechny tyto změněné soubory připravíte k zapsání a následně všechny připravené změny zapíšete. Cyklus může začít od začátku. Pracovní cyklus je znázorněn na obrázku 2-1. +Jakmile začnete soubory upravovat, Git je bude považovat za změněné, protože jste v nich od poslední revize provedli změny. Poté všechny tyto změněné soubory *připravíte k zapsání* (stage) a následně všechny připravené změny zapíšete (commit). A celý cyklus se opakuje. Pracovní cyklus je znázorněn na obrázku 2-1. Insert 18333fig0201.png Obrázek 2-1. Cyklus stavů vašich souborů @@ -54,23 +54,24 @@ Obrázek 2-1. Cyklus stavů vašich souborů Hlavním nástrojem na zjišťování stavu jednotlivých souborů je příkaz `git status`. Spustíte-li tento příkaz bezprostředně po klonování, objeví se zhruba následující: $ git status - # On branch master - nothing to commit (working directory clean) + On branch master + nothing to commit, working directory clean -To znamená, že žádné soubory nejsou připraveny k zapsání a pracovní adresář je čistý. Jinými slovy žádné sledované soubory nebyly změněny. Git také neví o žádných nesledovaných souborech, jinak by byly ve výčtu uvedeny. Příkaz vám dále sděluje, na jaké větvi (branch) se nacházíte. Pro tuto chvíli nebudeme situaci komplikovat a výchozí bude vždy hlavní větev (`master` branch). Větve a reference budou podrobně popsány v následující kapitole. +To znamená, že žádné soubory nejsou připraveny k zapsání a pracovní adresář je čistý. Jinými slovy, žádné sledované soubory nebyly změněny. Git také neví o žádných nesledovaných souborech, jinak by byly ve výčtu uvedeny. Příkaz vám dále sděluje, na jaké větvi (branch) se nacházíte. Pro tuto chvíli nebudeme situaci komplikovat a výchozí bude vždy hlavní větev (`master` branch). Větve a reference budou podrobně popsány v následující kapitole. -Řekněme, že nyní přidáte do projektu nový soubor, například soubor `README`. Pokud soubor neexistoval dříve a vy spustíte příkaz `git status`, bude nesledovaný soubor uveden takto: +Řekněme, že nyní přidáte do projektu nový soubor, například soubor `README`. Pokud soubor dříve neexistoval a vy spustíte příkaz `git status`, bude nesledovaný soubor uveden takto: $ vim README $ git status - # On branch master - # Untracked files: - # (use "git add ..." to include in what will be committed) - # - # README + On branch master + Untracked files: + (use "git add ..." to include in what will be committed) + + README + nothing added to commit but untracked files present (use "git add" to track) -Vidíte, že nový soubor `README` není sledován, protože je ve výpisu stavů uveden v části „Untracked files“. Není-li soubor sledován, obecně to znamená, že Git ví o souboru, který nebyl v předchozím snímku (v předchozí revizi), a nezařadí ho ani do dalších snímků, dokud mu k tomu nedáte výslovný příkaz. Díky tomu se nemůže stát, že budou do revizí nedopatřením zahrnuty vygenerované binární soubory nebo jiné soubory, které si nepřejete zahrnout. Vy si ale přejete soubor README zahrnout, a proto spusťme jeho sledování. +Vidíte, že nový soubor `README` není sledován, protože je ve výpisu stavů uveden v části „Untracked files“. Není-li soubor sledován, obecně to znamená, že Git ví o souboru, který nebyl v předchozím snímku (v předchozí revizi), a nezařadí ho ani do dalších snímků, dokud mu k tomu nedáte výslovný příkaz. Díky tomu se nemůže stát, že budou do revizí nedopatřením zahrnuty vygenerované binární soubory nebo jiné soubory, které si nepřejete zahrnout. Vy si ale přejete soubor README zahrnout, a proto ho začněme sledovat. ### Sledování nových souborů ### @@ -81,87 +82,89 @@ K zahájení sledování nových souborů se používá příkaz `git add`. Chce Když nyní znovu provedete příkaz k výpisu stavů (git status), uvidíte, že je nyní soubor `README` sledován a připraven k zapsání: $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README + Můžeme říci, že je připraven k zapsání, protože je uveden v části „Changes to be committed“, tedy „Změny k zapsání“. Pokud v tomto okamžiku zapíšete revizi, v historickém snímku bude verze souboru z okamžiku, kdy jste spustili příkaz `git add`. Možná si vzpomínáte, že když jste před časem spustili příkaz `git init`, provedli jste potom příkaz `git add (soubory)`. Příkaz jste zadávali kvůli zahájení sledování souborů ve vašem adresáři. Příkaz `git add` je doplněn uvedením cesty buď k souboru, nebo k adresáři. Pokud se jedná o adresář, příkaz přidá rekurzivně všechny soubory v tomto adresáři. -### Připravení změněných souborů ### +### Příprava změněných souborů k zapsání ### -Nyní provedeme změny v souboru, který už byl sledován. Pokud změníte už dříve sledovaný soubor s názvem `benchmarks.rb` a poté znovu spustíte příkaz `status`, zobrazí se výpis podobného obsahu: +Nyní provedeme změny v souboru, který už byl sledován. Pokud změníte už dříve sledovaný soubor s názvem `benchmarks.rb` a poté znovu spustíte příkaz `status`, zobrazí se něco takového: $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb -Soubor `benchmarks.rb` je uveden v části „Changes not staged for commit“ (Změněno, ale neaktualizováno). Znamená to, že soubor, který je sledován, byl v pracovním adresáři změněn, avšak ještě nebyl připraven k zapsání. Chcete-li ho připravit, spusťte příkaz `git add` (jedná se o univerzální příkaz – používá se k zahájení sledování nových souborů, k připravení souborů a k dalším operacím, jako např. k označení souborů, které kolidovaly při sloučení, za vyřešené). Spusťme nyní příkaz `git add` k připravení souboru `benchmarks.rb` k zapsání a následně znovu příkaz `git status`: + +Soubor `benchmarks.rb` je uveden v části „Changes not staged for commit“ (změny, které nejsou připraveny k zapsání). Znamená to, že soubor, který je sledován, byl v pracovním adresáři změněn, avšak ještě nebyl připraven k zapsání (staged). Chcete-li ho připravit k zapsání, spusťte příkaz `git add` (jedná se o víceúčelový příkaz – používá se k zahájení sledování nových souborů i k dalším operacím, jako je například označení vyřešených případů kolize souborů při slučování). Spusťme nyní příkaz `git add`, abychom soubor `benchmarks.rb` připravili k zapsání, a potom znovu zadejme příkaz `git status`: $ git add benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) -Oba soubory jsou nyní připraveny k zapsání a budou zahrnuty do příští revize. Nyní předpokládejme, že jste si vzpomněli na jednu malou změnu, kterou chcete ještě před zapsáním revize provést v souboru `benchmarks.rb`. Soubor znovu otevřete a provedete změnu. Soubor je připraven k zapsání. Spusťme však ještě jednou příkaz `git status`: + new file: README + modified: benchmarks.rb + + +Oba soubory jsou nyní připraveny k zapsání a budou zahrnuty do příští revize. Nyní předpokládejme, že jste si vzpomněli na jednu malou změnu, kterou chcete ještě před zapsáním revize provést v souboru `benchmarks.rb`. Soubor znovu otevřete, provedete změnu a chcete jej zapsat. Spusťme však ještě jednou příkaz `git status`: $ vim benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # modified: benchmarks.rb - # - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README + modified: benchmarks.rb + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) -Co to má být? Soubor `benchmarks.rb` je nyní uveden jak v části připraveno k zapsání (Changes to be committed), tak v části nepřipraveno k zapsání (Changes not staged for commit). Jak je tohle možné? Věc se má tak, že Git po spuštění příkazu `git add` připraví soubor přesně tak, jak je. Pokud nyní revizi zapíšete, bude obsahovat soubor `benchmarks.rb` tak, jak vypadal když jste naposledy spustili příkaz `git add`, nikoli v té podobě, kterou měl v pracovním adresáři v okamžiku, když jste spustili příkaz `git commit`. Pokud upravíte soubor po provedení příkazu `git add`, je třeba spustit `git add` ještě jednou, aby byla připravena aktuální verze souboru: + modified: benchmarks.rb + + +Co to má být? Soubor `benchmarks.rb` je nyní uveden jak v části připraveno k zapsání (Changes to be committed), tak v části nepřipraveno k zapsání (Changes not staged for commit). Jak je tohle možné? Věc se má tak, že Git po spuštění příkazu `git add` připraví soubor k zapsání přesně ve tvaru, v jakém se nachází v daném okamžiku. Pokud nyní revizi zapíšete, bude obsahovat soubor `benchmarks.rb` tak, jak vypadal, když jste naposledy spustili příkaz `git add`, nikoli v té podobě, kterou měl v pracovním adresáři v okamžiku, když jste spustili příkaz `git commit`. Pokud upravíte soubor po provedení příkazu `git add`, je třeba spustit `git add` ještě jednou, aby byla připravena aktuální verze souboru: $ git add benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README + modified: benchmarks.rb + ### Ignorované soubory ### -Často se ve vašem adresáři vyskytne skupina souborů, u nichž nebudete chtít, aby je Git automaticky přidával nebo aby je vůbec uváděl jako nesledované. Jedná se většinou o automaticky vygenerované soubory, jako soubory log nebo soubory vytvořené sestavovacím systémem. V takovém případě můžete vytvořit soubor `.gitignore`, který specifikuje ignorované soubory. Tady je malý příklad souboru `.gitignore`: +Ve vašem adresáři se často vyskytne skupina souborů, u nichž nebudete chtít, aby je Git automaticky přidával nebo aby je vůbec uváděl jako nesledované. Jedná se většinou o automaticky vygenerované soubory, jako soubory log nebo soubory vytvořené při překladu. V takových případech můžete vytvořit soubor `.gitignore` se seznamem masek pro ignorované soubory. Tady je malý příklad souboru `.gitignore`: $ cat .gitignore *.[oa] *~ -První řádek říká systému Git, že má ignorovat všechny soubory končící na `.o` nebo `.a` – objektové a archivní soubory, které mohou být výsledkem vytváření kódu. Druhý řádek systému Git říká, aby ignoroval všechny soubory končící vlnovkou (`~`), již mnoho textových editorů (např. Emacs) používá k označení dočasných souborů. Můžete rovněž přidat adresář `log`, `tmp` nebo `pid`, automaticky vygenerovanou dokumentaci apod. Nastavit soubor `.gitignore`, ještě než se pustíte do práce, bývá většinou dobrý nápad. Alespoň se vám nestane, že byste nedopatřením zapsali také soubory, o které v repozitáři Git nestojíte. +První řádek říká systému Git, že má ignorovat všechny soubory končící na `.o` nebo `.a` – *objekty* a *archivní* soubory, které mohou být výsledkem překladu. Druhý řádek systému Git říká, aby ignoroval všechny soubory končící vlnovkou (`~`), kterou mnoho textových editorů (např. Emacs) používá k označení dočasných souborů. Můžete rovněž přidat adresář `log`, `tmp` nebo `pid`, automaticky vygenerovanou dokumentaci a podobné. Vytvoření a naplnění souboru `.gitignore` ještě dříve než se pustíte do práce bývá většinou dobrý nápad. Alespoň se vám nestane, že byste nedopatřením zapsali také soubory, o které v repozitáři Git nestojíte. -Toto jsou pravidla pro masky, které můžete použít v souboru `.gitignore`: +Pravidla pro masky, které můžete použít v souboru `.gitignore`, jsou následující: * Prázdné řádky nebo řádky začínající znakem `#` budou ignorovány. -* Standardní masku souborů. +* Standardní masky souborů (glob patterns). * Chcete-li označit adresář, můžete masku zakončit lomítkem (`/`). * Pokud řádek začíná vykřičníkem (`!`), maska na něm je negována. @@ -180,25 +183,30 @@ Tady je další příklad souboru `.gitignore`: build/ # ignoruj doc/notes.txt, ale nikoli doc/server/arch.txt doc/*.txt + # ignoruj všechny .txt soubory v adresáři doc/ + doc/**/*.txt + +Část masky `**/` je v Gitu dostupná od verze 1.8.2. ### Zobrazení připravených a nepřipravených změn ### -Je-li pro vaše potřeby příkaz `git status` příliš neurčitý – chcete přesně vědět, co jste změnili, nejen které soubory – můžete použít příkaz `git diff`. Podrobněji se budeme příkazu `git diff` věnovat později. Vy ho však nejspíš budete nejčastěji využívat k zodpovězení těchto dvou otázek: Co jste změnili, ale ještě nepřipravili k zapsání? A co jste připravili a nyní může být zapsáno? Zatímco příkaz `git status` vám tyto otázky zodpoví velmi obecně, příkaz `git diff` přesně zobrazí přidané a odstraněné řádky – tedy samotná záplata. +Je-li pro vaše potřeby příkaz `git status` příliš neurčitý – chcete přesně vědět, co jste změnili, nejen které soubory – můžete použít příkaz `git diff`. Podrobněji se budeme příkazu `git diff` věnovat později. Vy ho však nejspíš budete nejčastěji využívat k zodpovězení těchto dvou otázek: Co jste změnili, ale ještě nepřipravili k zapsání? A co jste připravili a nyní může být zapsáno? Zatímco příkaz `git status` vám tyto otázky zodpoví velmi obecně, příkaz `git diff` přesně zobrazí přidané a odstraněné řádky – tedy samotnou záplatu. Řekněme, že znovu upravíte a připravíte soubor `README` a poté bez připravení upravíte soubor `benchmarks.rb`. Po spuštění příkazu `status` se zobrazí zhruba toto: $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + Chcete-li vidět, co jste změnili, avšak ještě nepřipravili k zapsání, zadejte příkaz `git diff` bez dalších parametrů: @@ -221,7 +229,7 @@ Chcete-li vidět, co jste změnili, avšak ještě nepřipravili k zapsání, za Tento příkaz srovná obsah vašeho pracovního adresáře a oblasti připravených změn. Výsledek vám ukáže provedené změny, které jste dosud nepřipravili k zapsání. -Chcete-li vidět, co jste připravili a co bude součástí příští revize, použijte a co bude součástí příští revize, použijte příkaz `git diff --cached`. (Ve verzích Git 1.6.1 a novějších můžete použít také příkaz `git diff --staged`, který se možná snáze pamatuje.) Tento příkaz srovná připravené změny s poslední revizí: +Chcete-li vidět, co jste připravili a co bude součástí příští revize, použijte příkaz `git diff --cached`. (Ve verzích Git 1.6.1 a novějších můžete použít také příkaz `git diff --staged`, který se možná snáze pamatuje.) Tento příkaz srovná připravené změny (staged changes) s poslední revizí: $ git diff --cached diff --git a/README b/README @@ -236,23 +244,25 @@ Chcete-li vidět, co jste připravili a co bude součástí příští revize, p + +Grit is a Ruby library for extracting information from a Git repository -K tomu je třeba poznamenat, že příkaz `git diff` sám o sobě nezobrazí všechny změny provedené od poslední revize, ale jen změny, které zatím nejsou připraveny. To může být občas matoucí, protože pokud jste připravili všechny provedené změny, výstup příkazu `git diff` bude prázdný. +K tomu je třeba poznamenat, že příkaz `git diff` sám o sobě nezobrazí všechny změny provedené od poslední revize, ale jen změny, které zatím nejsou připraveny. To může být občas matoucí, protože pokud jste připravili všechny provedené změny, bude výstup příkazu `git diff` prázdný. V dalším příkladu ukážeme situaci, kdy jste připravili soubor `benchmarks.rb` a poté ho znovu upravili. Příkaz `git diff` můžete nyní použít k zobrazení změn v souboru, které byly připraveny, a změn, které nejsou připraveny: $ git add benchmarks.rb $ echo '# test line' >> benchmarks.rb $ git status - # On branch master - # - # Changes to be committed: - # - # modified: benchmarks.rb - # - # Changes not staged for commit: - # - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: benchmarks.rb + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + Příkaz `git diff` nyní můžete použít k zobrazení změn, které dosud nejsou připraveny: @@ -288,12 +298,12 @@ A příkaz `git diff --cached` ukáže změny, které už připraveny jsou: ### Zapisování změn ### -Nyní, když jste seznam připravených změn nastavili podle svých představ, můžete začít zapisovat změny. Nezapomeňte, že všechno, co dosud nebylo připraveno k zapsání – všechny soubory, které jste vytvořili nebo změnili a na které jste po úpravách nepoužili příkaz `git add` – nebudou do revize zahrnuty. Zůstanou na vašem disku ve stavu „změněno“. -Když jsme v našem případě naposledy spustili příkaz `git status`, viděli jste, že všechny soubory byly připraveny k zapsání. Nyní může proběhnout samotné zapsání změn. Nejjednodušším způsobem zapsání je zadat příkaz `git commit`: +Nyní, když jste seznam připravených změn nastavili podle svých představ, můžete začít zapisovat změny. Nezapomeňte, že všechno, co dosud nebylo připraveno k zapsání – všechny soubory, které jste vytvořili nebo změnili a na které jste po úpravách nepoužili příkaz `git add` –, nebudou do revize zahrnuty. Zůstanou na vašem disku jako změněné soubory. +Když jste v našem případě naposledy spustili příkaz `git status`, viděli jste, že všechny soubory byly připraveny k zapsání. Takže jste připraveni k samotnému zapsání změn. Nejjednodušší způsob zapsání změn spočívá v použití příkazu `git commit`: $ git commit -Po zadání příkazu se otevře zvolený editor. (Ten je nastaven proměnnou prostředí `$EDITOR` vašeho shellu. Většinou se bude jednat o editor vim nebo emacs, ale pomocí příkazu `git config --global core.editor` můžete nastavit i jakýkoli jiný – viz kapitola 1.) +Po zadání příkazu se otevře vámi zvolený editor. (Ten je nastaven proměnnou prostředí `$EDITOR` vašeho shellu. Většinou se bude jednat o editor vim nebo emacs, ale pomocí příkazu `git config --global core.editor` můžete nastavit i jakýkoli jiný – viz *kapitola 1*.) Editor zobrazí následující text (tento příklad je z editoru Vim): @@ -301,75 +311,76 @@ Editor zobrazí následující text (tento příklad je z editoru Vim): # with '#' will be ignored, and an empty message aborts the commit. # On branch master # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # # new file: README # modified: benchmarks.rb + # ~ ~ ~ ".git/COMMIT_EDITMSG" 10L, 283C -Jak vidíte, výchozí zpráva k revizi (commit message) obsahuje zakomentovaný aktuální výstup příkazu `git status` a nahoře jeden prázdný řádek. Tyto komentáře můžete odstranit a napsat vlastní zprávu k revizi, nebo je můžete v souboru ponechat, abyste si lépe vzpomněli, co bylo obsahem dané revize. (Chcete-li zařadit ještě podrobnější informace o tom, co jste měnili, můžete k příkazu `git commit` přidat parametr `-v`. V editoru se pak zobrazí také výstup „diff“ ke konkrétním změnám a vy přesně uvidíte, co bylo změněno.) Jakmile editor zavřete, Git vytvoří revizi se zprávou, kterou jste napsali (s odstraněnými komentáři a rozdíly). +Jak vidíte, výchozí zpráva k revizi (commit message) obsahuje zakomentovaný aktuální výstup příkazu `git status` a nahoře jeden prázdný řádek. Tyto komentáře můžete odstranit a napsat vlastní zprávu k revizi, nebo je můžete v souboru ponechat, abyste si lépe vzpomněli, co bylo obsahem dané revize. (Chcete-li zařadit ještě podrobnější informace o tom, co jste měnili, můžete k příkazu `git commit` přidat parametr `-v`. V editoru se pak zobrazí také výstup rozdílů (diff) ke konkrétním změnám a vy přesně uvidíte, co bylo změněno.) Jakmile editor zavřete, Git vytvoří revizi se zprávou, kterou jste napsali (s odstraněnými komentáři a rozdíly). Zprávu k revizi můžete rovněž napsat do řádku k příkazu `commit`. Jako zprávu ji označíte tak, že před ni vložíte příznak `-m`: $ git commit -m "Story 182: Fix benchmarks for speed" - [master]: created 463dc4f: "Fix benchmarks for speed" - 2 files changed, 3 insertions(+), 0 deletions(-) + [master 463dc4f] Story 182: Fix benchmarks for speed + 2 files changed, 3 insertions(+) create mode 100644 README -Nyní jste vytvořili svou první revizi! Vidíte, že se po zapsání revize zobrazil výpis s informacemi: do jaké větve jste revizi zapsali (hlavní, `master`), jaký kontrolní součet SHA-1 revize dostala (`463dc4f`), kolik souborů bylo změněno a statistiku přidaných a odstraněných řádků revize. +Nyní jste vytvořili svou první revizi! Vidíte, že se po zapsání revize zobrazil výpis s informacemi: do jaké větve jste revizi zapsali (`master`), jaký je kontrolní součet SHA-1 revize (`463dc4f`), kolik souborů bylo změněno a statistiku přidaných a odstraněných řádků revize. -Nezapomeňte, že revize zaznamená snímek projektu, jak je obsažen v oblasti připravených změn. Vše, co jste nepřipravili k zapsání, zůstane ve stavu „změněno“ na vašem disku. Chcete-li i tyto soubory přidat do své historie, zapište další revizi. Pokaždé, když zapíšete revizi, nahrajete snímek svého projektu, k němuž se můžete později vrátit nebo ho můžete použít k srovnání. +Nezapomeňte, že revize zaznamená snímek projektu, jak je obsažen v oblasti připravených změn. Vše, co jste nepřipravili k zapsání, zůstane ve stavu změněno na vašem disku. Chcete-li i tyto soubory přidat do své historie, zapište další revizi. Pokaždé, když zapíšete revizi, nahrajete snímek svého projektu, k němuž se můžete později vrátit nebo ho můžete použít k srovnání. ### Přeskočení oblasti připravených změn ### -Přestože může být oblast připravených změn opravdu užitečným nástrojem pro přesné vytváření revizí, je někdy při daném pracovním postupu zbytečným mezikrokem. Chcete-li oblast připravených změn úplně přeskočit, nabízí Git jednoduchou zkratku. Přidáte-li k příkazu `git commit` parametr `-a`, Git do revize automaticky zahrne každý soubor, který je sledován. Zcela tak odpadá potřeba zadávat příkaz `git add`: +Přestože může být oblast připravených změn opravdu užitečným nástrojem pro přesné vytváření revizí, je někdy při daném pracovním postupu zbytečným mezikrokem. Chcete-li oblast připravených změn úplně přeskočit, nabízí Git jednoduchou zkratku. Přidáte-li k příkazu `git commit` parametr `-a`, Git do revize automaticky zahrne každý soubor, který je sledován. Odpadá potřeba zadávat příkaz `git add`: $ git status - # On branch master - # - # Changes not staged for commit: - # - # modified: benchmarks.rb - # + On branch master + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + + no changes added to commit (use "git add" and/or "git commit -a") $ git commit -a -m 'added new benchmarks' [master 83e38c7] added new benchmarks - 1 files changed, 5 insertions(+), 0 deletions(-) + 1 files changed, 5 insertions(+) -Tímto způsobem není nutné provádět před zapsáním revize příkaz `git add` pro soubor `benchmarks.rb`. +Povšimněte si, že kvůli souboru `benchmarks.rb` v tomto případě nemusíte před zapsáním revize provádět příkaz `git add`. ### Odstraňování souborů ### Chcete-li odstranit soubor ze systému Git, musíte ho odstranit ze sledovaných souborů (přesněji řečeno odstranit z oblasti připravených změn) a zapsat revizi. Odstranění provedete příkazem `git rm`, který odstraní soubor zároveň z vašeho pracovního adresáře, a proto ho už příště neuvidíte mezi nesledovanými soubory. -Pokud soubor jednoduše odstraníte z pracovního adresáře, zobrazí se ve výpisu `git status` v části „Changes not staged for commit“ (tedy nepřipraveno): +Pokud soubor jednoduše odstraníte z pracovního adresáře, zobrazí se ve výpisu `git status` v části „Changes not staged for commit“ (tedy *nepřipraveno*): $ rm grit.gemspec $ git status - # On branch master - # - # Changes not staged for commit: - # (use "git add/rm ..." to update what will be committed) - # - # deleted: grit.gemspec - # + On branch master + Changes not staged for commit: + (use "git add/rm ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + deleted: grit.gemspec + + no changes added to commit (use "git add" and/or "git commit -a") Pokud nyní provedete příkaz `git rm`, bude k zapsání připraveno odstranění souboru: $ git rm grit.gemspec rm 'grit.gemspec' $ git status - # On branch master - # - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # deleted: grit.gemspec - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) -Po příštím zapsání revize soubor zmizí a nebude sledován. Pokud už jste soubor upravili a přidali do indexu, musíte odstranění provést pomocí parametru `-f`. Jedná se o bezpečnostní funkci, jež má zabránit nechtěnému odstranění dat, která ještě nebyla nahrána do snímku, a nemohou proto být ze systému Git obnovena. + deleted: grit.gemspec + + +Po příštím zapsání revize soubor zmizí a přestane být sledován. Pokud už jste soubor upravili a přidali do indexu, musíte odstranění provést pomocí parametru `-f`. Jedná se o bezpečnostní funkci, jež má zabránit nechtěnému odstranění dat, která ještě nebyla nahrána do snímku, a nemohou proto být ze systému Git obnovena. Další užitečnou možností, která se vám může hodit, je zachování souboru v pracovním stromě a odstranění z oblasti připravených změn. Soubor tak ponecháte na svém pevném disku, ale ukončíte jeho sledování systémem Git. To může být užitečné zejména v situaci, kdy něco zapomenete přidat do souboru `.gitignore`, a omylem to tak zahrnete do revize, např. velký log soubor nebo pár zkompilovaných souborů s příponou `.a`. V takovém případě použijte parametr `--cached`: @@ -387,7 +398,7 @@ Tento příkaz odstraní všechny soubory, které končí vlnovkou (`~`). ### Přesouvání souborů ### -Na rozdíl od ostatních systémů VCS nesleduje Git explicitně přesouvání souborů. Pokud přejmenujete v systému Git soubor, neuloží se žádná metadata s informací, že jste soubor přejmenovali. Git však používá jinou fintu, aby zjistil, že byl soubor přejmenován. Na ni se podíváme později. +Na rozdíl od ostatních systémů pro správu verzí nesleduje Git explicitně přesouvání souborů. Pokud soubor v systému Git přejmenujete, neuloží se žádná metadata s informací, že jste soubor přejmenovali. Git však používá jinou fintu, aby zjistil, že byl soubor přejmenován. Na ni se podíváme později. Může se zdát zvláštní, že Git přesto používá příkaz `mv`. Chcete-li v systému Git přejmenovat soubor, můžete spustit třeba příkaz @@ -395,22 +406,20 @@ Může se zdát zvláštní, že Git přesto používá příkaz `mv`. Chcete-li a vše funguje na výbornou. A skutečně, pokud takový příkaz provedete a podíváte se na stav souboru, uvidíte, že ho Git považuje za přejmenovaný (renamed): - $ git mv README.txt README + $ git mv README README.txt $ git status - # On branch master - # Your branch is ahead of 'origin/master' by 1 commit. - # - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # renamed: README.txt -> README - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + renamed: README -> README.txt + Výsledek je však stejný, jako byste provedli následující: - $ mv README.txt README - $ git rm README.txt - $ git add README + $ mv README README.txt + $ git rm README + $ git add README.txt Git implicitně zjistí, že se jedná o přejmenování, a proto nehraje roli, zda přejmenujete soubor tímto způsobem, nebo pomocí příkazu `mv`. Jediným skutečným rozdílem je, že `mv` je jediný příkaz, zatímco u druhého způsobu potřebujete příkazy tři — příkaz `mv` je pouze zjednodušením. Důležitější je, že můžete použít jakýkoli způsob přejmenování a příkaz add/rm provést později, před zapsáním revize. @@ -422,7 +431,7 @@ Následující příklady ukazují velmi jednoduchý projekt pojmenovaný `simpl git clone git://github.com/schacon/simplegit-progit.git -Po zadání příkazu `git log` v tomto projektu byste měli dostat výstup, který vypadá zhruba následovně: +Po zadání příkazu `git log` v tomto projektu byste měli dostat výstup, který vypadá zhruba takto: $ git log commit ca82a6dff817ec66f44342007202690a93763949 @@ -443,11 +452,11 @@ Po zadání příkazu `git log` v tomto projektu byste měli dostat výstup, kte first commit -Ve výchozím nastavení a bez dalších parametrů vypíše příkaz `git log` revize provedené v daném repozitáři v obráceném chronologickém pořadí. Nejnovější revize tak budou uvedeny nahoře. Jak vidíte, tento příkaz vypíše všechny revize s jejich kontrolním součtem SHA-1, jménem a e-mailem autora, datem zápisu a zprávou k revizi. +Ve výchozím nastavení a bez dalších parametrů vypíše příkaz `git log` revize provedené v daném repozitáři v obráceném chronologickém pořadí. Nejnovější revize tak budou uvedeny nahoře. Jak vidíte, tento příkaz vypíše všechny revize s jejich kontrolním součtem SHA-1, jménem a e-mailem autora, datem zápisu a zprávou o revizi. -K příkazu `git log` je k dispozici velké množství nejrůznějších parametrů, díky nimž můžete najít přesně to, co hledáte. Vyjmenujme některé z nejčastěji používaných parametrů. +K příkazu `git log` je k dispozici velké množství nejrůznějších parametrů, díky nimž můžete zobrazit přesně to, co potřebujete. Ukážeme si některé z nejpoužívanějších možností. -Jedním z nejužitečnějších je parametr `-p`, který zobrazí rozdíly diff provedené v každé revizi. Můžete také použít parametr `-2`, který omezí výpis pouze na dva poslední záznamy: +Jedním z nejužitečnějších je parametr `-p`, který zobrazí rozdíly (diff) provedené v každé revizi. Můžete také použít parametr `-2`, který omezí výpis pouze na dva poslední záznamy: $ git log -p -2 commit ca82a6dff817ec66f44342007202690a93763949 @@ -460,11 +469,13 @@ Jedním z nejužitečnějších je parametr `-p`, který zobrazí rozdíly diff index a874b73..8f94139 100644 --- a/Rakefile +++ b/Rakefile - @@ -5,7 +5,7 @@ require 'rake/gempackagetask' + @@ -5,5 +5,5 @@ require 'rake/gempackagetask' spec = Gem::Specification.new do |s| + s.name = "simplegit" - s.version = "0.1.0" + s.version = "0.1.1" s.author = "Scott Chacon" + s.email = "schacon@gee-mail.com commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 Author: Scott Chacon @@ -488,6 +499,27 @@ Jedním z nejužitečnějších je parametr `-p`, který zobrazí rozdíly diff \ No newline at end of file Tento parametr zobrazí tytéž informace, ale za každým záznamem následuje informace o rozdílech. Tato funkce je velmi užitečná při kontrole kódu nebo k rychlému zjištění, co bylo obsahem série revizí, které přidal váš spolupracovník. + +Někdy se změny kontrolují snadněji na úrovni slov než na úrovni řádků. Git nabízí parametr `--word-diff`, který můžeme přidat za příkaz `git log -p`. Místo obvyklé detekce rozdílů po řádcích získáme rozdíly po slovech. Zjišťování rozdílů po slovech je u zdrojového kódu celkem k ničemu, ale pokud porovnáváme velké textové soubory -- jako například knihy nebo vaši disertační práci --, pak se tato možnost hodí. Tady máme příklad: + + $ git log -U1 --word-diff + commit ca82a6dff817ec66f44342007202690a93763949 + Author: Scott Chacon + Date: Mon Mar 17 21:52:11 2008 -0700 + + changed the version number + + diff --git a/Rakefile b/Rakefile + index a874b73..8f94139 100644 + --- a/Rakefile + +++ b/Rakefile + @@ -7,3 +7,3 @@ spec = Gem::Specification.new do |s| + s.name = "simplegit" + s.version = [-"0.1.0"-]{+"0.1.1"+} + s.author = "Scott Chacon" + +Jak vidíte, výstup neobsahuje žádné přidané a odstraněné řádky, jak tomu bývá u běžného zobrazení rozdílů (diff). Místo toho se změny zobrazují uvnitř textu. Přidaná slova jsou uzavřena mezi značkami `{+ +}` a odstraněná jsou uzavřena v `[- -]`. Možná byste také rádi zredukovali obvyklé třířádkové okolí změny na pouhý jeden řádek, protože chcete znát okolí slova a ne okolí řádku. Můžeme toho dosáhnout zadáním parametru `-U1`, jako ve výše uvedeném příkladu. + Ve spojení s příkazem `git log` můžete použít také celou řadu shrnujících parametrů. Pokud například chcete zobrazit některé stručné statistiky pro každou revizi, použijte parametr `--stat`: $ git log --stat @@ -498,7 +530,7 @@ Ve spojení s příkazem `git log` můžete použít také celou řadu shrnujíc changed the version number Rakefile | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) + 1 file changed, 1 insertion(+), 1 deletion(-) commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 Author: Scott Chacon @@ -507,7 +539,7 @@ Ve spojení s příkazem `git log` můžete použít také celou řadu shrnujíc removed unnecessary test code lib/simplegit.rb | 5 ----- - 1 files changed, 0 insertions(+), 5 deletions(-) + 1 file changed, 5 deletions(-) commit a11bef06a3f659402fe7563abf99ad00de2209e6 Author: Scott Chacon @@ -518,7 +550,7 @@ Ve spojení s příkazem `git log` můžete použít také celou řadu shrnujíc README | 6 ++++++ Rakefile | 23 +++++++++++++++++++++++ lib/simplegit.rb | 25 +++++++++++++++++++++++++ - 3 files changed, 54 insertions(+), 0 deletions(-) + 3 files changed, 54 insertions(+) Jak vidíte, parametr `--stat` vypíše pod každým záznamem revize seznam změněných souborů, kolik souborů bylo změněno (changed) a kolik řádků bylo v těchto souborech vloženo (insertions) a smazáno (deletions). Zároveň vloží na konec výpisu shrnutí těchto informací. Další opravdu užitečnou možností je parametr `--pretty`. Tento parametr změní výstup logu na jiný než výchozí formát. K dispozici máte několik přednastavených možností. Parametr `oneline` vypíše všechny revize na jednom řádku. Tuto možnost oceníte při velkém množství revizí. Dále se nabízejí parametry `short`, `full` a `fuller` (zkrácený, plný, úplný). Zobrazují výstup přibližně ve stejném formátu, avšak s více či méně podrobnými informacemi: @@ -537,13 +569,18 @@ Nejzajímavějším parametrem je pak `format`, který umožňuje definovat vlas Tabulka 2-1 uvádí některé užitečné parametry, které format akceptuje. + + Parametr Popis výstupu %H Otisk (hash) revize %h Zkrácený otisk revize %T Otisk stromu %t Zkrácený otisk stromu - %P Nadřazené otisky - %p Zkrácené nadřazené otisky + %P Otisky rodičovských revizí + %p Zkrácené otisky rodičovských revizí %an Jméno autora %ae E-mail autora %ad Datum autora (formát je možné nastavit parametrem --date) @@ -554,7 +591,7 @@ Tabulka 2-1 uvádí některé užitečné parametry, které format akceptuje. %cr Datum autora revize, relativní %s Předmět -Možná se ptáte, jaký je rozdíl mezi autorem a autorem revize. Autor je osoba, která práci původně napsala, zatímco autor revize je osoba, která práci zapsala do repozitáře. Pokud tedy pošlete záplatu k projektu a některý z ústředních členů (core members) ji použije, do výpisu se dostanete oba – vy jako autor a core member jako autor revize. K tomuto rozlišení se blíže dostaneme v kapitole 5. +Možná se ptáte, jaký je rozdíl mezi *autorem* a *autorem revize*. *Autor* (author) je osoba, která práci původně napsala, zatímco *autor revize* (committer) je osoba, která práci zapsala do repozitáře. Pokud tedy pošlete záplatu k projektu a některý z ústředních členů (core members) ji použije, do výpisu se dostanete oba – vy jako autor a core member jako autor revize. K tomuto rozlišení se blíže dostaneme v *kapitole 5*. Parametry `oneline` a `format` jsou zvlášť užitečné ve spojení s další možností `log`u – parametrem `--graph`. Tento parametr vloží pěkný malý ASCII graf, znázorňující historii vaší větve a slučování, kterou si ukážeme na naší kopii repozitáře projektu Grit: @@ -572,8 +609,14 @@ Parametry `oneline` a `format` jsou zvlášť užitečné ve spojení s další To je jen několik základních parametrů k formátování výstupu pro příkaz `git log`, celkově jich je mnohem více. Tabulka 2-2 uvádí parametry, které jsme už zmínili, a některé další běžné parametry formátování, které mohou být užitečné. Pravý sloupec popisuje, jak který parametr změní výstup `log`u. + + Parametr Popis -p Zobrazí záplatu vytvořenou s každou revizí. + --word-diff Zobrazí záplatu ve tvaru rozdílu po slovech. --stat Zobrazí statistiku pro změněné soubory v každé revizi. --shortstat Zobrazí pouze řádek změněno/vloženo/smazáno z příkazu --stat. --name-only Za informacemi o revizi zobrazí seznam změněných souborů. @@ -581,7 +624,7 @@ To je jen několik základních parametrů k formátování výstupu pro příka --abbrev-commit Zobrazí pouze prvních několik znaků kontrolního součtu SHA-1 místo všech 40. --relative-date Zobrazí datum v relativním formátu (např. "2 weeks ago", tj. před 2 týdny) místo formátu s úplným datem. --graph Zobrazí vedle výstupu logu ASCII graf k historii větve a slučování. - --pretty Zobrazí revize v alternativním formátu. Parametry příkazu jsou oneline, short, full, fuller a format (lze zadat vlastní formát). + --pretty Zobrazí revize v alternativním formátu. Parametry příkazu jsou oneline, short, full, fuller a format (ve kterém uvedete svůj vlastní formát). --oneline Užitečná zkratka pro `--pretty=oneline --abbrev-commit`. ### Omezení výstupu logu ### @@ -594,12 +637,19 @@ Velmi užitečné jsou naproti tomu časově omezující parametry, jako `--sinc Tento příkaz pracuje s velkým množstvím formátů. Můžete zadat konkrétní datum („2008-01-15“) nebo relativní datum, např. „2 years 1 day 3 minutes ago“ (před 2 roky, 1 dnem a 3 minutami). -Z výpisu rovněž můžete filtrovat pouze revize, které odpovídají určitým kritériím. Parametr `--author` umožňuje filtrovat výpisy podle konkrétního autora, pomocí parametru `--grep` můžete ve zprávách k revizím vyhledávat klíčová slova. Chcete-li hledat současný výskyt parametrů author i grep, musíte přidat výraz `--all-match`, jinak se bude hledat kterýkoli z nich. +Z výpisu rovněž můžete filtrovat pouze revize, které odpovídají určitým kritériím. Parametr `--author` umožňuje filtrovat výpisy podle konkrétního autora, pomocí parametru `--grep` můžete ve zprávách k revizím vyhledávat klíčová slova. (Všimněte si, že pokud použijete současně parametry author a grep, bude příkaz vyhledávat záznamy splňující obojí.) + +Pokud chcete zadat více parametrů grep, musíte přidat výraz `--all-match`, jinak se bude hledat kterýkoli z nich. Posledním opravdu užitečným parametrem, který lze přidat k příkazu `git log` , je zadání cesty. Jestliže zadáte název adresáře nebo souboru, výstup logu tím omezíte na revize, které provedly změnu v těchto souborech. Cesta je vždy posledním parametrem a většinou jí předcházejí dvě pomlčky (`--`) , jimiž je oddělena od ostatních parametrů. Tabulka 2-3 uvádí pro přehlednost zmíněné parametry a několik málo dalších. Tabulka 2.2 + + Parametr Popis -(n) Zobrazí pouze posledních n revizí. --since, --after Omezí výpis na revize provedené po zadaném datu. @@ -607,10 +657,55 @@ Tabulka 2-3 uvádí pro přehlednost zmíněné parametry a několik málo dalš --author Zobrazí pouze revize, v nichž autor odpovídá zadanému řetězci. --committer Zobrazí pouze revize, v nichž autor revize odpovídá zadanému řetězci. -Pokud chcete například zjistit, které revize upravující testovací soubory byly v historii zdrojového kódu Git zapsány v říjnu 2008 Juniem Hamanem a nebyly sloučením, můžete zadat následující příkaz: - $ git log --pretty="%h - %s" --author=gitster --since="2008-10-01" \ - --before="2008-11-01" --no-merges -- t/ +### Omezení výstupního logu na určité datum nebo čas ### + +Pokud chcete zjistit, které revize (commit) v repozitáři se zdrojovým kódem Git (git://git.kernel.org/pub/scm/git/git.git) mají datum zápisu (CommitDate) 2014-04-29 -- relativně k vašemu lokálnímu časovému pásmu (takovému, jaké je nastaveno na vašem počítači), použijte příkaz + + $ git log --after="2014-04-29 00:00:00" --before="2014-04-29 23:59:59" \ + --pretty=fuller + +Protože se výstup bude lišit podle časového pásma v místě spuštění, doporučuje se v argumentech `--after` a `--before` vždy používat absolutní čas (například ve formátu ISO 8601, který obsahuje i informaci o časovém pásmu). Činíme tak proto, aby každý, kdo stejný příkaz spustí, obdržel stejné, opakovatelné výsledky. + +Pokud chceme získat zápisy z určitého časového okamžiku (například z 29. dubna 2013 v 17:07:22 středoevropského času), můžeme použít příkaz + + $ git log --after="2013-04-29T17:07:22+0200" \ + --before="2013-04-29T17:07:22+0200" --pretty=fuller + + commit de7c201a10857e5d424dbd8db880a6f24ba250f9 + Author: Ramkumar Ramachandra + AuthorDate: Mon Apr 29 18:19:37 2013 +0530 + Commit: Junio C Hamano + CommitDate: Mon Apr 29 08:07:22 2013 -0700 + + git-completion.bash: lexical sorting for diff.statGraphWidth + + df44483a (diff --stat: add config option to limit graph width, + 2012-03-01) added the option diff.startGraphWidth to the list of + configuration variables in git-completion.bash, but failed to notice + that the list is sorted alphabetically. Move it to its rightful place + in the list. + + Signed-off-by: Ramkumar Ramachandra + Signed-off-by: Junio C Hamano + +Výše uvedené časy (`AuthorDate`, `CommitDate`) se zobrazují v základním tvaru (`--date=default`), který zobrazuje informaci o časovém pásmu autora nebo přispěvatele. + +K dalším užitečným formátům patří `--date=iso` (ISO 8601), `--date=rfc` (RFC 2822), `--date=raw` (sekundy od počátku (epoch; 1970-01-01 UTC)), `--date=local` (časy ve vašem lokálním časovém pásmu) a také `--date=relative` (jako například "2 hours ago", tj. před dvěma hodinami). + +Pokud použijete příkaz `git log` bez určení času, uvažuje se čas odpovídající okamžiku spuštění na vašem počítači (používá stejný posun vůči UTC). + +Pokud například na vašem počítači spustíte `git log` v 09:00 a vaše časové pásmo je vůči greenwichskému času posunuto o tři hodiny vpřed, pak se výsledek následujících dvou příkazů shoduje: + + $ git log --after=2008-06-01 --before=2008-07-01 + $ git log --after="2008-06-01T09:00:00+0300" \ + --before="2008-07-01T09:00:00+0300" + +A poslední příklad. Pokud chcete zjistit, které revize upravující testovací soubory ve zdrojovém kódu Git zapsal Junio Hamano v říjnu 2008 (relativě k časové zóně New Yorku) a které přitom nebyly sloučením (merge), můžete zadat následující příkaz: + + $ git log --pretty="%h - %s" --author=gitster \ + --after="2008-10-01T00:00:00-0400" \ + --before="2008-10-31T23:59:59-0400" --no-merges -- t/ 5610e3b - Fix testcase failure when extended attribute acd3b9e - Enhance hold_lock_file_for_{update,append}() f563754 - demonstrate breakage of detached checkout wi @@ -618,7 +713,7 @@ Pokud chcete například zjistit, které revize upravující testovací soubory 51a94af - Fix "checkout --track -b newbranch" on detac b0ad11e - pull: allow "git pull origin $something:$cur -Z téměř 20 000 revizí v historii zdrojového kódu Git zobrazí tento příkaz 6 záznamů, které odpovídají zadaným kritériím. +Z více než 36 tisíc revizí v historii zdrojového kódu Git zobrazí tento příkaz 6 záznamů, které odpovídají zadaným kritériím. ### Grafické uživatelské rozhraní pro procházení historie ### @@ -631,11 +726,11 @@ V horní polovině okna vidíte historii revizí, doplněnou názorným hierarch ## Rušení změn ## -Kdykoli si můžete přát zrušit nějakou provedenou změnu. Podívejme se proto, jaké základní nástroje se nám tu nabízejí. Ale buďte opatrní! Ne všechny zrušené změny se dají vrátit. Je to jedna z mála oblastí v systému Git, kdy při neuváženém postupu riskujete, že přijdete o část své práce. +Kdykoli se může stát, že byste nějakou úpravu chtěli vrátit do původního stavu.. Podívejme se proto, jaké základní nástroje se nám tu nabízejí. Ale buďte opatrní! Ne všechny zrušené změny se dají vrátit. Je to jedna z mála oblastí v systému Git, kdy při neuváženém postupu riskujete, že přijdete o část své práce. ### Změna poslední revize ### -Jedním z nejčastějších rušení úprav je situace, kdy zapíšete revizi příliš brzy a ještě jste např. zapomněli přidat některé soubory nebo byste rádi změnili zprávu k revizi. Chcete-li opravit poslední revizi, můžete spustit příkaz commit s parametrem `--amend`: +Jedním z nejčastějších důvodů pro rušení úprav je situace, kdy zapíšete revizi příliš brzy a ještě jste například zapomněli přidat některé soubory, nebo byste rádi změnili zprávu k revizi. Chcete-li opravit poslední revizi, můžete spustit příkaz commit s parametrem `--amend`: $ git commit --amend @@ -649,39 +744,40 @@ Pokud například zapíšete revizi a potom si uvědomíte, že jste zapomněli $ git add forgotten_file $ git commit --amend -Tyto tři příkazy vytvoří jedinou revizi – třetí příkaz nahradí výsledky prvního. +Provedení uvedených tří příkazů zůstane jediná revize – druhý příkaz `commit` nahradí výsledky prvního. -### Návrat souboru z oblasti připravených změn ### +### Odstranění souboru z oblasti připravených změn ### -Následující dvě části popisují, jak vrátit změny provedené v oblasti připravených změn a v pracovním adresáři. Je příjemné, že příkaz, jímž se zjišťuje stav těchto dvou oblastí, zároveň připomíná, jak v nich zrušit nežádoucí změny. Řekněme například, že jste změnili dva soubory a chcete je zapsat jako dvě oddělené změny, jenže omylem jste zadali příkaz `git add *` a oba soubory jste tím připravili k zapsání. Jak lze tyto dva soubory vrátit z oblasti připravených změn? Připomene vám to příkaz `git status`: +Následující dvě části popisují, jak se poprat s oblastí připravených změn a se změnami v pracovním adresáři. Je příjemné, že příkaz, jímž se zjišťuje stav těchto dvou oblastí, zároveň připomíná, jak v nich nežádoucí změny zrušit. Řekněme například, že jste změnili dva soubory a chcete je zapsat jako dvě oddělené změny. Jenže omylem jste zadali příkaz `git add *` a oba soubory jste tím připravili k zapsání. Jak lze tyto dva soubory vrátit z oblasti připravených změn? Připomene vám to příkaz `git status`: $ git add . $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # modified: README.txt - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: README.txt + modified: benchmarks.rb + Přímo pod nadpisem „Changes to be committed“ (Změny k zapsání) se říká: pro návrat z oblasti připravených změn použijte příkaz `git reset HEAD ...` Budeme se tedy řídit touto radou a vrátíme soubor `benchmarks.rb` z oblasti připravených změn: $ git reset HEAD benchmarks.rb - benchmarks.rb: locally modified + Unstaged changes after reset: + M benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # modified: README.txt - # - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # (use "git checkout -- ..." to discard changes in working directory) - # - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: README.txt + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + Příkaz je sice trochu zvláštní, ale funguje. Soubor `benchmarks.rb` má stav „změněn“, ale už se nenachází v oblasti připravených změn. @@ -689,44 +785,44 @@ Příkaz je sice trochu zvláštní, ale funguje. Soubor `benchmarks.rb` má sta A co když zjistíte, že nechcete zachovat změny, které jste provedli v souboru `benchmarks.rb`? Jak je můžete snadno zrušit a vrátit soubor zpět do podoby při poslední revizi (nebo při prvním klonování nebo v jakémkoli okamžiku, kdy jste ho zaznamenali v pracovním adresáři)? Příkaz `git status` vám naštěstí řekne, co dělat. U posledního příkladu vypadá oblast připravených změn takto: - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # (use "git checkout -- ..." to discard changes in working directory) - # - # modified: benchmarks.rb - # + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + Výpis vám sděluje, jak zahodit změny (discard changes), které jste provedli (přinejmenším tak činí novější verze systému Git, od verze 1.6.1; pokud máte starší verzi, doporučujeme ji aktualizovat, čímž získáte některé z těchto vylepšených funkcí). Uděláme, co nám výpis radí: $ git checkout -- benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # modified: README.txt - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: README.txt -Jak vidíte, změny byly zahozeny. Všimněte si také, že se jedná o nebezpečný příkaz. Veškeré změny, které jste v souboru provedli, jsou ztraceny, soubor jste právě překopírovali jiným souborem. Nikdy tento příkaz nepoužívejte, pokud si nejste zcela jisti, že už daný soubor nebudete potřebovat. Pokud potřebujete pouze odstranit soubor z cesty, podívejte se na odkládání a větvení v následující kapitole. Tyto postupy většinou bývají vhodnější. -Vše, co je zapsáno v systému Git, lze téměř vždy obnovit. Obnovit lze dokonce i revize na odstraněných větvích nebo revize, které byly přepsány revizí `--amend` (o obnovování dat viz kapitola 9). Pokud však dojde ke ztrátě dat, která dosud nebyla součástí žádné revize, bude tato ztráta patrně nevratná. +Jak vidíte, změny byly zahozeny. Všimněte si také, že se jedná o nebezpečný příkaz. Veškeré změny, které jste v souboru provedli, jsou ztraceny, soubor jste právě překopírovali jiným souborem. Nikdy tento příkaz nepoužívejte, pokud si nejste zcela jisti, že už daný soubor nebudete potřebovat. Pokud potřebujete pouze odstranit soubor z cesty, podívejte se na odkládání (stashing) a větvení v následující kapitole. Tyto postupy většinou bývají vhodnější. + +Zapamatujte si, že vše, co je zapsáno v systému Git, lze téměř vždy obnovit. Obnovit lze dokonce i revize na odstraněných větvích nebo revize, které byly přepsány revizí `--amend` (o obnovování dat viz *kapitola 9*). Pokud však dojde ke ztrátě dat, která dosud nebyla součástí žádné revize, bude tato ztráta patrně nevratná. ## Práce se vzdálenými repozitáři ## -Abyste mohli spolupracovat na projektech v systému Git, je třeba vědět, jak manipulovat se vzdálenými repozitáři (remote repositories). Vzdálené repozitáře jsou verze vašeho projektu umístěné na internetu nebo kdekoli v síti. Vzdálených repozitářů můžete mít hned několik, každý pro vás přitom bude buď pouze ke čtení (read-only) nebo ke čtení a zápisu (read write). Spolupráce s ostatními uživateli zahrnuje také manipulaci s těmito vzdálenými repozitáři. Chcete-li svou práci sdílet, je nutné ji posílat do repozitářů a také ji z nich stahovat. -Při manipulaci se vzdálenými repozitáři je nutné vědět, jak lze přidat vzdálený repozitář, jak odstranit repozitář, který už není platný, jak spravovat různé vzdálené větve, jak je definovat jako sledované či nesledované apod. V této části se zaměříme právě na správu vzdálených repozitářů. +Abyste mohli spolupracovat na projektech v systému Git, je třeba vědět, jak manipulovat se vzdálenými repozitáři (remote repositories). Vzdálené repozitáře jsou verze vašeho projektu umístěné na Internetu nebo kdekoli v síti. Vzdálených repozitářů můžete mít hned několik, každý pro vás přitom bude buď pouze ke čtení (read-only) nebo ke čtení a zápisu (read write). Spolupráce s ostatními uživateli zahrnuje také správu těchto vzdálených repozitářů. Při sdílení práce musíte do těchto repozitářů data odesílat (push) a zase je z nich stahovat (pull). +Při správě vzdálených repozitářů musíte vědět, jak lze přidat vzdálený repozitář, jak odstranit vzdálený repozitář, který už není platný, jak spravovat různé vzdálené větve, jak je definovat jako sledované či nesledované a další věci. V této části se zaměříme právě na správu vzdálených repozitářů. ### Zobrazení vzdálených serverů ### -Chcete-li zjistit, jaké vzdálené servery máte nakonfigurovány, můžete použít příkaz `git remote`. Systém vypíše zkrácené názvy všech identifikátorů vzdálených repozitářů, jež máte zadány. Pokud byl váš repozitář vytvořen klonováním, měli byste vidět přinejmenším server origin. Origin je výchozí název, který Git dává serveru, z nějž jste repozitář klonovali. +Chcete-li zjistit, jaké vzdálené servery máte nakonfigurovány, můžete použít příkaz `git remote`. Systém vypíše krátké názvy, přes které se se vzdálenými repozitáři manipuluje, a které jste dříve určili. Pokud byl váš repozitář vytvořen klonováním, měli byste vidět přinejmenším server *origin*. Jde o výchozí název, který Git dává serveru, z nějž jste repozitář klonovali. $ git clone git://github.com/schacon/ticgit.git - Initialized empty Git repository in /private/tmp/ticgit/.git/ - remote: Counting objects: 595, done. - remote: Compressing objects: 100% (269/269), done. - remote: Total 595 (delta 255), reused 589 (delta 253) - Receiving objects: 100% (595/595), 73.31 KiB | 1 KiB/s, done. - Resolving deltas: 100% (255/255), done. + Cloning into 'ticgit'... + remote: Reusing existing pack: 1857, done. + remote: Total 1857 (delta 0), reused 0 (delta 0) + Receiving objects: 100% (1857/1857), 374.35 KiB | 193.00 KiB/s, done. + Resolving deltas: 100% (772/772), done. + Checking connectivity... done. $ cd ticgit $ git remote origin @@ -737,7 +833,7 @@ Můžete rovněž zadat parametr `-v`, jenž zobrazí adresu URL, kterou má Git origin git://github.com/schacon/ticgit.git (fetch) origin git://github.com/schacon/ticgit.git (push) -Pokud máte více než jeden vzdálený repozitář, příkaz je vypíše všechny. Například můj repozitář Grit vypadá takto: +Pokud používáte více než jeden vzdálený repozitář, příkaz je vypíše všechny. Například můj repozitář Grit vypadá takto: $ cd grit $ git remote -v @@ -747,11 +843,11 @@ Pokud máte více než jeden vzdálený repozitář, příkaz je vypíše všech koke git://github.com/koke/grit.git origin git@github.com:mojombo/grit.git -To znamená, že můžeme velmi snadno stáhnout příspěvky od kteréhokoli z těchto uživatelů. Nezapomeňte však, že pouze vzdálený server origin je SSH URL, a je tedy jediným repozitářem, kam lze posílat soubory (důvod objasníme v kapitole 4). +To znamená, že mohu velmi snadno stáhnout příspěvky od kteréhokoli z těchto uživatelů. Ale všimněte si, že pouze vzdálený server origin je SSH URL, a je tedy jediným repozitářem, kam lze soubory odesílat (push; důvod objasníme v *kapitole 4*). ### Přidávání vzdálených repozitářů ### -V předchozích částech už jsem se letmo dotkl přidávání vzdálených repozitářů. V této části se dostávám k tomu, jak přesně při přidávání postupovat. Chcete-li přidat nový vzdálený repozitář Git ve formě zkráceného názvu, na nějž lze snadno odkazovat, spusťte příkaz `git remote add [zkrácený název] [url]`: +V předchozích částech už jsem se letmo dotkl přidávání vzdálených repozitářů. V této části se dostávám k tomu, jak přesně při přidávání postupovat. Chcete-li přidat nový vzdálený repozitář Git a zadat zkrácený název, přes který se můžete snadno odkazovat, spusťte příkaz `git remote add [zkrácený název] [url]`: $ git remote origin @@ -771,7 +867,7 @@ V předchozích částech už jsem se letmo dotkl přidávání vzdálených rep * [new branch] master -> pb/master * [new branch] ticgit -> pb/ticgit -Paulova hlavní větev (master branch) je lokálně dostupná jako `pb/master`. Můžete ji začlenit do některé ze svých větví nebo tu můžete provést checkout lokální větve, jestliže si ji chcete prohlédnout. +Paulova hlavní větev (master branch) je teď lokálně dostupná jako `pb/master`. Můžete ji začlenit (merge) do některé ze svých větví, nebo ji můžete zpřístupnit jako lokální větev (check out), jestliže si ji chcete prohlédnout. ### Vyzvedávání a stahování ze vzdálených repozitářů ### @@ -779,19 +875,19 @@ Jak jste právě viděli, data ze vzdálených projektů můžete získat pomoc $ git fetch [název vzdáleného repozitáře] -Příkaz zamíří do vzdáleného projektu a stáhne z něj všechna data, která ještě nevlastníte. Poté byste měli mít reference na všechny větve tohoto vzdáleného projektu. Nyní je můžete kdykoli slučovat nebo prohlížet. (Podrobněji se budeme větvím a jejich použití věnovat v kapitole 3.) +Příkaz zamíří do vzdáleného projektu a stáhne z něj všechna data, která ještě nemáte u sebe. Poté byste měli mít k dispozici odkazy na všechny větve tohoto vzdáleného projektu. Od toho okamžiku je můžete kdykoli slučovat nebo prohlížet. (Podrobněji se budeme větvím a jejich použití věnovat v *kapitole 3*.) -Pokud jste naklonovali repozitář, příkaz automaticky přiřadí tento vzdálený repozitář pod název „origin“. Příkaz `git fetch origin` tak vyzvedne veškerou novou práci, která byla na server poslána (push) od okamžiku, kdy jste odsud klonovali (popř. odsud naposledy vyzvedávali práci). Měli bychom zmínit, že příkaz `fetch` stáhne data do vašeho lokálního repozitáře, v žádném případě ale data automaticky nesloučí s vaší prací ani jinak nezmění nic z toho, na čem právě pracujete. Data ručně sloučíte se svou prací, až to uznáte za vhodné. +Pokud jste naklonovali repozitář, příkaz automaticky přidá tento vzdálený repozitář pod názvem *origin*. Takže příkaz `git fetch origin` vyzvedne veškerou novou práci, která byla na uvedený server poslána (push) od okamžiku, kdy jste odtud klonovali (nebo kdy jste odtud naposledy vyzvedávali práci). Měli bychom zmínit, že příkaz `fetch` stáhne data do vašeho lokálního repozitáře. V žádném případě ale data automaticky nesloučí s vaší prací ani jinak nezmění nic z toho, na čem právě pracujete. Sloučení s vaší prací musíte udělat ručně, až to uznáte za vhodné. -Pokud máte větev nastavenou ke sledování vzdálené větve (více informací naleznete v následující části a v kapitole 3), můžete použít příkaz `git pull`, který automaticky vyzvedne a poté začlení vzdálenou větev do vaší aktuální větve. Tento postup pro vás může být snazší a pohodlnější. Standardně přitom příkaz `git clone` automaticky nastaví vaši lokální hlavní větev, aby sledovala vzdálenou hlavní větev na serveru, z nějž jste klonovali (za předpokladu, že má vzdálený server hlavní větev). Příkaz `git pull` většinou vyzvedne data ze serveru, z nějž jste původně klonovali, a automaticky se pokusí začlenit je do kódu, na němž právě pracujete. +Pokud máte větev nastavenou ke sledování vzdálené větve (více informací naleznete v následující části a v *kapitole 3*), můžete použít příkaz `git pull`, který automaticky vyzvedne (fetch) a poté začlení (merge) vzdálenou větev do vaší aktuální větve. Tento postup pro vás může být snazší a pohodlnější. Standardně přitom příkaz `git clone` automaticky nastaví vaši lokální hlavní větev, aby sledovala vzdálenou hlavní větev na serveru, z kterého jste klonovali (za předpokladu, že má vzdálený server hlavní větev). Příkaz `git pull` většinou vyzvedne data ze serveru, z něhož jste původně klonovali, a automaticky se pokusí začlenit je do kódu, na němž právě pracujete. -### Posílání do vzdálených repozitářů ### +### Odesílání do vzdálených repozitářů ### -Pokud se váš projekt nachází ve fázi, kdy ho chcete sdílet s ostatními, můžete ho odeslat (push) na vzdálený server. Příkaz pro tuto akci je jednoduchý: `git push [název vzdáleného repozitáře] [název větve]`. Pokud chcete poslat svou hlavní větev na server `origin` (i tady platí, že proces klonování vám nastaví názvy `master` i `origin` automaticky), můžete k odeslání své práce na server použít tento příkaz: +Pokud se váš projekt nachází ve stavu, kdy ho chcete sdílet s ostatními, můžete ho odeslat (push) na vzdálený server. Příkaz pro tuto akci je jednoduchý: `git push [název vzdáleného repozitáře] [název větve]`. Pokud chcete poslat svou hlavní větev na server `origin` (i tady platí, že proces klonování vám nastaví názvy `master` i `origin` automaticky), můžete k odeslání své práce na server použít tento příkaz: $ git push origin master -Tento příkaz bude funkční, pouze pokud jste klonovali ze serveru, k němuž máte oprávnění pro zápis, a pokud sem od vašeho klonování nikdo neposílal svou práci. Pokud spolu s vámi provádí současně klonování ještě někdo další a ten poté svou práci odešle na server, vaše později odesílaná práce bude oprávněně odmítnuta. Nejprve musíte stáhnout práci ostatních a začlenit ji do své, teprve potom vám server umožní odeslání. Více informací o odesílání na vzdálené servery najdete v kapitole 3. +Tento příkaz bude funkční, pouze pokud jste klonovali ze serveru, k němuž máte oprávnění pro zápis, a pokud sem od vašeho klonování nikdo neposílal svou práci. Pokud spolu s vámi provádí současně klonování ještě někdo další a ten poté svou práci odešle na server, vaše později odesílaná práce bude oprávněně odmítnuta. Nejprve musíte stáhnout práci ostatních a začlenit ji do své, teprve potom vám server umožní odeslání. Více informací o odesílání na vzdálené servery najdete v *kapitole 3*. ### Prohlížení vzdálených repozitářů ### @@ -806,9 +902,9 @@ Jestliže chcete získat více informací o konkrétním vzdáleném repozitář master ticgit -Bude obsahovat adresu URL vzdáleného repozitáře a informace ke sledování větví. Příkaz vám mimo jiné sděluje, že pokud se nacházíte na hlavní větvi (branch master) a spustíte příkaz `git pull`, automaticky začlení (merge) práci do hlavní větve na vzdáleném serveru, jakmile vyzvedne všechny vzdálené reference. Součástí výpisu jsou také všechny vzdálené reference, které příkaz stáhl. +Bude obsahovat adresu URL vzdáleného repozitáře a informace ke sledování větví. Příkaz vám mimo jiné sděluje, že pokud se nacházíte na hlavní větvi (branch `master`) a spustíte příkaz `git pull`, pak se po vyzvednutí všech vzdálených referencí (fetch) práce z hlavní větve na vzdáleném serveru automaticky začlení (merge). Součástí výpisu jsou také všechny vzdálené reference, které příkaz stáhl. -Toto je jednoduchý příklad, s nímž se můžete setkat. Pokud však Git používáte na pokročilé bázi, příkaz `git remote show` vám patrně zobrazí podstatně více informací: +S uvedeným jednoduchým případem se pravděpodobně setkáte. Pokud však Git používáte na intenzivněji, může vám příkaz `git remote show` zobrazit mnohem více informací: $ git remote show origin * remote origin @@ -832,11 +928,11 @@ Toto je jednoduchý příklad, s nímž se můžete setkat. Pokud však Git pou Local branch pushed with 'git push' master:master -Tento příkaz vám ukáže, která větev bude automaticky odeslána, pokud spustíte příkaz `git push` na určitých větvích. Příkaz vám také oznámí, které vzdálené větve na serveru ještě nemáte, které vzdálené větve máte, jež už byly ze serveru odstraněny, a několik větví, které budou automaticky sloučeny, jestliže spustíte příkaz `git pull`. +Tento příkaz ukazuje, která větev bude automaticky odeslána, pokud spustíte příkaz `git push` na určitých větvích. Příkaz vám také oznámí, které vzdálené větve na serveru ještě nemáte, které vzdálené větve máte, ale ze serveru už byly odstraněny, a několik větví, které budou automaticky sloučeny, jestliže spustíte příkaz `git pull`. -### Přesouvání a přejmenovávání vzdálených repozitářů ### +### Odstraňování a přejmenovávání vzdálených repozitářů ### -Chcete-li přejmenovat vzdálený repozitář, můžete v novějších verzích systému Git spustit příkaz `git remote rename`. Příkazem lze změnit zkrácený název vzdáleného repozitáře. Pokud například chcete přejmenovat repozitář z `pb` na `paul`, můžete tak učinit pomocí příkazu `git remote rename`: +Chcete-li změnit zkrácené jméno vzdáleného repozitáře, můžete v novějších verzích systému Git spustit příkaz `git remote rename`. Pokud například chcete přejmenovat repozitář z `pb` na `paul`, můžete tak učinit příkazem `git remote rename`: $ git remote rename pb paul $ git remote @@ -845,7 +941,7 @@ Chcete-li přejmenovat vzdálený repozitář, můžete v novějších verzích Za zmínku stojí, že tímto příkazem změníte zároveň i názvy vzdálených větví. Z původní reference `pb/master` se tak nyní stává `paul/master`. -Chcete-li, ať už z jakéhokoli důvodu, odstranit referenci (např. jste přesunuli server nebo už nepoužíváte dané zrcadlo, popř. přispěvatel přestal přispívat), můžete využít příkaz `git remote rm`: +Chcete-li, ať už z jakéhokoli důvodu, odstranit referenci (přesunuli jste například server nebo už nepoužíváte dané zrcadlo, nebo třeba přispěvatel přestal přispívat), můžete využít příkaz `git remote rm`: $ git remote rm paul $ git remote @@ -853,7 +949,7 @@ Chcete-li, ať už z jakéhokoli důvodu, odstranit referenci (např. jste přes ## Značky ## -Stejně jako většina systémů VCS nabízí i Git možnost označovat v historii určitá místa, jež považujete za důležitá. Tato funkce se nejčastěji používá k označení jednotlivých vydání (např. `v1.0`). V této části vysvětlíme, jak pořídíte výpis všech dostupných značek, jak lze vytvářet značky nové a jaké typy značek se vám nabízejí. +Stejně jako většina systémů VCS nabízí i Git možnost označovat v historii určitá místa, jež považujete za důležitá. Tato funkce se nejčastěji používá k označení jednotlivých vydání (například `v1.0`). V této části vysvětlíme, jak pořídíte výpis všech dostupných značek, jak lze vytvářet značky nové a jaké typy značek se vám nabízejí. ### Výpis značek ### @@ -897,6 +993,7 @@ Informace značky se zobrazí spolu s revizí, kterou značka označuje, po zad Date: Mon Feb 9 14:45:11 2009 -0800 my version 1.4 + commit 15027957951b64cf874c3557a0f3547bd83b3ff6 Merge: 4a447f7... a6b4c97... Author: Scott Chacon @@ -1030,7 +1127,7 @@ Můžete se podívat, že jste revizi označil: ### Sdílení značek ### -Příkaz `git push` nepřenáší značky na vzdálené servery automaticky. Pokud jste vytvořili značku, budete ji muset na sdílený server poslat ručně. Tento proces je stejný jako sdílení vzdálených větví. Spusťte příkaz `git push origin [název značky]`. +Příkaz `git push` nepřenáší značky na vzdálené servery automaticky. Pokud jste vytvořili značku, budete ji muset na sdílený server poslat explicitně. Tento proces je stejný jako sdílení vzdálených větví. Spusťte příkaz `git push origin [název značky]`. $ git push origin v1.5 Counting objects: 50, done. @@ -1058,17 +1155,17 @@ Pokud nyní někdo bude klonovat nebo stahovat z vašeho repozitáře, stáhne r ## Tipy a triky ## -Než ukončíme tuto kapitolu o základech práce se systémem Git, přidáme ještě pár tipů a triků, které vám mohou usnadnit či zpříjemnit práci. Mnoho uživatelů pracuje se systémem Git, aniž by tyto triky znali a používali. V dalších částech knihy se už o nich nebudeme zmiňovat ani nebudeme předpokládat, že je používáte. Přesto pro vás mohou být užitečné. +Než ukončíme tuto kapitolu věnovanou základům práce se systémem Git, přidáme ještě pár tipů a triků, které vám mohou usnadnit či zpříjemnit práci. Mnoho uživatelů pracuje se systémem Git, aniž by tyto triky znali a používali. V dalších částech knihy se už o nich nebudeme zmiňovat ani nebudeme předpokládat, že je používáte. Přesto pro vás mohou být užitečné. ### Automatické dokončování ### -Jestliže používáte shell Bash, nabízí vám Git možnost zapnout si skript automatického dokončování. Stáhněte si zdrojový kód Git a podívejte se do adresáře `contrib/completion`. Měli byste tam najít soubor s názvem `git-completion.bash`. Zkopírujte tento soubor do svého domovského adresáře a přidejte ho do souboru `.bashrc`: +Jestliže používáte shell Bash, nabízí vám Git možnost zapnout si skript pro automatické dokončování. Stáhněte si jej ze zdrojových textů systému Git z https://github.com/git/git/blob/master/contrib/completion/git-completion.bash. Soubor nakopírujte tento do vašeho domovského adresáře a do souboru `.bashrc` přidejte: - source ~/.git-completion.bash + source ~/git-completion.bash -Chcete-li nastavit Git tak, aby měl automaticky dokončování pro shell Bash pro všechny uživatele, zkopírujte tento skript do adresáře `/opt/local/etc/bash_completion.d` v systémech Mac nebo do adresáře `/etc/bash_completion.d/` v systémech Linux. Toto je adresář skriptů, z nějž Bash automaticky načítá pro shellové dokončování. +Chcete-li nastavit Git tak, aby měl automaticky dokončování pro shell Bash pro všechny uživatele, zkopírujte u systému Mac tento skript do adresáře `/opt/local/etc/bash_completion.d`, nebo u systémů Linux do adresáře `/etc/bash_completion.d/`. Jde o adresář skriptů, ze kterého si Bash automaticky načítá podporu pro shellové dokončování. -Pokud používáte Git Bash v systému Windows (Git Bash je výchozím programem při instalaci systému Git v OS Windows pomocí msysGit), mělo by být automatické dokončování přednastaveno. +Pokud používáte Git Bash v systému Windows (Git Bash je pro instalaci msysGit pod Windows výchozím programem), mělo by být automatické dokončování přednastaveno. Při zadávání příkazu Git stiskněte klávesu Tab a měla by se objevit nabídka, z níž můžete zvolit příslušné dokončení: @@ -1077,7 +1174,7 @@ Při zadávání příkazu Git stiskněte klávesu Tab a měla by se objevit nab Pokud zadáte – stejně jako v našem příkladu nahoře – `git co` a dvakrát stisknete klávesu Tab, systém vám navrhne „commit“ a „config“. Doplníte-li ještě `m`, skript automaticky dokončí příkaz na `git commit`. -Automatické dokončování pravděpodobně více využijete v případě parametrů. Pokud například zadáváte příkaz `git log` a nemůžete si vzpomenout na některý z parametrů, můžete zadat jeho začátek a stisknout klávesu Tab, aby vám systém navrhl možná dokončení. +Automatické dokončování pravděpodobně více využijete v případě parametrů. Pokud například zadáváte příkaz `git log` a nemůžete si vzpomenout na některý z parametrů, můžete zadat jeho začátek, stisknout klávesu Tab a podívat se, co by to mohlo přesně být: $ git log --s --shortstat --since= --src-prefix= --stat --summary diff --git a/cs/03-git-branching/01-chapter3.markdown b/cs/03-git-branching/01-chapter3.markdown index 8d5275ffe..95f3afe98 100644 --- a/cs/03-git-branching/01-chapter3.markdown +++ b/cs/03-git-branching/01-chapter3.markdown @@ -1,23 +1,23 @@ # Větve v systému Git # -Téměř každý systém VCS podporuje do určité míry větvení. Větvení znamená, že se můžete odloučit od hlavní linie vývoje a pokračovat v práci, aniž byste tuto hlavní linii zanášeli. V mnoha VCS nástrojích se může jednat o poněkud náročný proces, který často vyžaduje vytvoření nové kopie adresáře se zdrojovým kódem. To může – zvláště u velkých projektů – trvat poměrně dlouho. +Téměř každý systém pro správu verzí podporuje do určité míry větvení. Větvení znamená, že se můžete odloučit od hlavní linie vývoje a pokračovat v práci, aniž byste hlavní linii zanášeli smetím. V mnoha VCS nástrojích se může jednat o poněkud náročný proces, který často vyžaduje vytvoření nové kopie adresáře se zdrojovým kódem. To může – zvláště u velkých projektů – trvat poměrně dlouho. -Někteří lidé mluví o modelu větvení v systému Git jako o jeho exkluzivní funkci. Není sporu o tom, že je Git díky tomuto modelu v komunitě VCS poměrně jedinečný. V čem je jeho větvení ojedinělé? Větvení je v systému Git neuvěřitelně lehké a operace s ním související probíhají téměř okamžitě. Stejně rychlé je i přepínání mezi jednotlivými větvemi. Na rozdíl od ostatních systémů VCS Git podporuje způsob práce s bohatým větvením a častým slučováním, a to i několikrát za den. Pokud tuto funkci pochopíte a zvládnete její ovládání, dostanete do ruky výkonný a unikátní nástroj, který doslova změní váš pohled na vývoj. +Někteří lidé mluví o modelu větvení v systému Git jako o převratné vlastnosti. Není sporu o tom, že je Git díky tomu ve skupině systémů pro správu verzí poměrně jedinečný. V čem je jeho větvení tak zvláštní? Větvení je v systému Git neuvěřitelně snadné a operace s ním související probíhají téměř okamžitě. A stejně rychlé je i přepínání mezi jednotlivými větvemi. Na rozdíl od ostatních systémů pro správu verzí vybízí Git ke způsobu práce s bohatým větvením a častým slučováním, a to i několikrát za den. Pokud tuto funkci pochopíte a zvládnete její ovládání, dostanete do ruky výkonný a unikátní nástroj, který doslova změní váš pohled na vývoj. ## Co je to větev ## Abychom skutečně pochopili, jak funguje v systému Git větvení, budeme se muset vrátit o krok zpět a podívat se, jak Git ukládá data. Jak si možná vzpomínáte z kapitoly 1, Git neukládá data jako sérii změn nebo rozdílů, ale jako sérii snímků. -Zapíšete-li v systému Git revizi, Git uloží objekt revize, obsahující ukazatel na snímek obsahu, který jste určili k zapsání, metadata o autorovi a zprávě a nula nebo více ukazatelů na revizi nebo revize, které byly přímými rodiči této revize – žádné rodiče nemá první revize, jednoho rodiče má běžná revize a několik rodičů mají revize, které vznikly sloučením ze dvou či více větví. +Zapíšete-li v systému Git revizi, Git uloží objekt revize, obsahující ukazatel na snímek obsahu, který jste určili k zapsání, metadata o autorovi a zprávě a nula nebo více ukazatelů na revizi nebo revize, které byly přímými rodiči této revize: žádné rodiče nemá první revize, jednoho rodiče má běžná revize a několik rodičů mají revize, které vznikly sloučením ze dvou či více větví. -Pro ilustraci předpokládejme, že máte adresář se třemi soubory, které připravíte k zapsání a následně zapíšete. S připravením souborů k zapsání proběhne u každého z nich kontrolní součet (o otisku SHA-1 jsme se zmínili v kapitole 1), daná verze souborů se uloží v repozitáři Git (Git na ně odkazuje jako na bloby) a přidá jejich kontrolní součet do oblasti připravených změn: +Pro ilustraci předpokládejme, že máte adresář se třemi soubory, které připravíte k zapsání a následně zapíšete. Při přípravě souborů k zapsání je pro každý z nich vypočítán kontrolní součet (o otisku SHA-1 jsme se zmínili v kapitole 1), daná verze souborů se uloží v repozitáři Git (Git na ně odkazuje jako na bloby) a přidá jejich kontrolní součet do oblasti připravených změn: $ git add README test.rb LICENSE $ git commit -m 'initial commit of my project' Vytvoříte-li revizi příkazem `git commit`, provede Git kontrolní součet každého adresáře (v tomto případě pouze kořenového adresáře projektu) a uloží tyto objekty stromu v repozitáři Git. Poté vytvoří objekt revize s metadaty a ukazatelem na kořenový strom projektu, aby mohl v případě potřeby tento snímek obnovit. -Váš repozitář Git nyní obsahuje pět objektů: jeden blob pro obsah každého ze tří vašich souborů, jeden strom, který zaznamenává obsah adresáře a udává, které názvy souborů jsou uloženy jako který blob, a jednu revizi s ukazatelem na kořenový strom a se všemi metadaty revize. Data ve vašem repozitáři Git se dají schematicky znázornit jako na obrázku 3-1. +Váš gitovský repozitář nyní obsahuje pět objektů: jeden blob pro obsah každého ze tří vašich souborů, jeden strom, který zaznamenává obsah adresáře a udává, které názvy souborů jsou uloženy jako který blob, a jeden objekt revize s ukazatelem na kořenový strom a se všemi metadaty revize. Data ve vašem repozitáři Git se dají schematicky znázornit jako na obrázku 3-1. Insert 18333fig0301.png Obrázek 3-1. Repozitář s daty jedné revize @@ -41,7 +41,7 @@ Tento příkaz vytvoří nový ukazatel na stejné revizi, na níž se právě n Insert 18333fig0304.png Obrázek 3-4. Několik větví ukazujících do historie dat revizí -Jak Git pozná, na jaké větvi se právě nacházíte? Používá speciální ukazatel zvaný HEAD. Nenechte se mást, tento HEAD je velmi odlišný od všech koncepcí v ostatních systémech VCS, na něž jste možná zvyklí, jako Subversion nebo CVS. V systému Git se jedná o ukazatel na lokální větev, na níž se právě nacházíte. V našem případě jste však stále ještě na hlavní větvi. Příkazem git branch jste pouze vytvořili novou větev, zatím jste na ni nepřepnuli (viz obrázek 3-5). +Jak Git pozná, na jaké větvi se právě nacházíte? Používá speciální ukazatel zvaný HEAD. Nenechte se mást, tento HEAD je velmi odlišný od všech koncepcí v ostatních systémech pro správu verzí, na něž jste možná zvyklí, jako Subversion nebo CVS. V systému Git se jedná o ukazatel na lokální větev, na níž se právě nacházíte. V našem případě jste však stále ještě na hlavní větvi. Příkazem `git branch` jste pouze vytvořili novou větev, zatím jste na ni nepřepnuli (viz obrázek 3-5). Insert 18333fig0305.png Obrázek 3-5. Soubor HEAD ukazující na větev, na níž se nacházíte. @@ -86,11 +86,11 @@ Nyní se historie vašeho projektu rozdělila (viz obrázek 3-9). Vytvořili jst Insert 18333fig0309.png Obrázek 3-9. Historie větví se rozdělila. -Vzhledem k tomu, že větev v systému Git tvoří jeden jednoduchý soubor, obsahující 40 znaků kontrolního součtu SHA-1 revize, na niž ukazuje, je snadné větve vytvářet i odstraňovat. Vytvořit novou větev je právě tak snadné a rychlé jako zapsat 41 bytů do souboru (40 znaků a jeden nový řádek). +Vzhledem k tomu, že větev v systému Git tvoří jeden jednoduchý soubor, obsahující 40 znaků kontrolního součtu SHA-1 revize, na niž ukazuje, je snadné větve vytvářet i odstraňovat. Vytvořit novou větev je právě tak snadné a rychlé jako zapsat 41 bytů do souboru (40 znaků a jeden znak pro nový řádek). Tato metoda se výrazně liší od způsobu, jakým probíhá větvení v ostatních nástrojích VCS, kde je nutné zkopírovat všechny soubory projektu do jiného adresáře. To může zabrat – podle velikosti projektu – několik sekund i minut, zatímco v systému Git probíhá tento proces vždy okamžitě. A protože při zapisování revize zaznamenáváme její rodiče, probíhá vyhledávání příslušné základny pro sloučení automaticky a je většinou velmi snadné. Tyto funkce slouží k tomu, aby se vývojáři nebáli vytvářet a používat nové větve. -Podívejme se, jaké výhody jim z toho plynou. +Podívejme se, proč byste to měli dělat také tak. ## Základy větvení a slučování ## @@ -100,7 +100,7 @@ Vytvořme si jednoduchý příklad větvení a slučování s pracovním postupe 2. Vytvoříte větev pro novou část stránek, v níž budete pracovat. 3. Vytvoříte práci v této větvi. -V tomto okamžiku vám zavolají, že se vyskytla jiná kritická chyba, která vyžaduje hotfix. Uděláte následující: +V tomto okamžiku vám zavolají, že se vyskytla jiná kritická chyba, která vyžaduje rychlou opravu (hotfix). Uděláte následující: 1. Vrátíte se zpět na produkční větev. 2. Vytvoříte větev pro přidání hotfixu. @@ -117,7 +117,7 @@ Obrázek 3-10. Krátká a jednoduchá historie revizí Rozhodli jste se, že budete pracovat na chybě č. 53, ať už vaše společnost používá jakýkoli systém sledování chyb. Přesněji řečeno, Git není začleněn do žádného konkrétního systému sledování chyb, ale protože je chyba č. 53 významná a chcete na ní pracovat, vytvoříte si pro ni novou větev. Abyste vytvořili novou větev a rovnou na ni přepnuli, můžete spustit příkaz `git checkout` s přepínačem `-b`: $ git checkout -b iss53 - Switched to a new branch "iss53" + Switched to a new branch 'iss53' Tímto způsobem jste spojili dva příkazy: @@ -129,43 +129,43 @@ Obrázek 3-11 ukazuje výsledek. Insert 18333fig0311.png Obrázek 3-11. Vytvoření nového ukazatele na větev -Pracujete na webových stránkách a zapíšete několik revizí. S každou novou revizí se větev `iss53` posune vpřed, protože jste provedli její checkout (to znamená, že jste na ni přepnuli a ukazuje na ni soubor HEAD – viz obrázek 3-12): +Pracujete na webových stránkách a zapíšete několik revizí. S každou novou revizí se větev `iss53` posune vpřed, protože jste provedli její checkout (to znamená, že na ni přepnuli ukazuje HEAD – viz obrázek 3-12): $ vim index.html - $ git commit -a -m 'added a new footer [issue 53]' + $ git commit -a -m 'add a new footer [issue 53]' Insert 18333fig0312.png Obrázek 3-12. Větev iss53 se s vaší prací posouvá vpřed. V tomto okamžiku vám zavolají, že se na webových stránkách vyskytl problém, který musíte okamžitě vyřešit. Jelikož pracujete v systému Git, nemusíte svou opravu vytvářet uprostřed změn, které jste provedli v části `iss53`, ani nemusíte dělat zbytečnou práci, abyste všechny tyto změny vrátili, než budete moci začít pracovat na opravě produkční verze stránek. Jediné, co teď musíte udělat, je přepnout zpět na hlavní větev. -Než tak učiníte, zkontrolujte, zda nemáte v pracovním adresáři nebo v oblasti připravených změn nezapsané změny, které kolidují s větví, jejíž checkout provádíte. V takovém případě by vám Git přepnutí větví nedovolil. Při přepínání větví je ideální, pokud máte čistý pracovní stav. Existují způsoby, jak toho docílit (jmenovitě odložení a doplnění revize), těm se však budeme věnovat až později. Pro tuto chvíli jste zapsali všechny provedené změny a můžete přepnout zpět na hlavní větev. +Než tak učiníte, zkontrolujte, zda nemáte v pracovním adresáři nebo v oblasti připravených změn nezapsané změny, které kolidují s větví, jejíž checkout provádíte. V takovém případě by vám Git přepnutí větví nedovolil. Při přepínání větví je ideální, pokud máte čistý pracovní stav. Existují způsoby, jak to obejít (jmenovitě odložení (stashing) a doplnění revize (commit amending)), těm se však budeme věnovat až později. Pro tuto chvíli jste zapsali všechny provedené změny a můžete přepnout zpět na hlavní větev. $ git checkout master - Switched to branch "master" + Switched to branch 'master' -V tomto okamžiku vypadá váš pracovní adresář přesně tak, jak vypadal, než jste začali pracovat na chybě č. 53, a vy se nyní můžete soustředit na rychlou opravu. Na paměti byste však stále měli mít následující: Git vždy vrátí pracovní adresář do stejného stavu, jak vypadal snímek revize, na niž ukazuje větev, jejíž checkout nyní provádíte. Automaticky budou přidány, odstraněny a upraveny soubory tak, aby byla vaše pracovní kopie totožná se stavem větve v okamžiku, kdy jste na ni zapsali poslední revizi. +V tomto okamžiku vypadá váš pracovní adresář přesně tak, jak vypadal, než jste začali pracovat na chybě č. 53, a vy se nyní můžete soustředit na rychlou opravu. Tento důležitý bod si zapamatujte: Git vždy vrátí pracovní adresář do stejného stavu, jak vypadal snímek revize, na niž ukazuje větev, jejíž checkout nyní provádíte. Automaticky budou přidány, odstraněny a upraveny soubory tak, aby byla vaše pracovní kopie totožná se stavem větve v okamžiku, kdy jste na ni zapsali poslední revizi. Nyní přichází na řadu hotfix. Vytvořme větev s hotfixem, v níž budeme pracovat, dokud nebude oprava hotová (viz obrázek 3-13): $ git checkout -b hotfix - Switched to a new branch "hotfix" + Switched to a new branch 'hotfix' $ vim index.html - $ git commit -a -m 'fixed the broken email address' - [hotfix]: created 3a0874c: "fixed the broken email address" - 1 files changed, 0 insertions(+), 1 deletions(-) + $ git commit -a -m 'fix the broken email address' + [hotfix 3a0874c] fix the broken email address + 1 files changed, 1 deletion(-) Insert 18333fig0313.png Obrázek 3-13. Větev „hotfix“ začleněná zpět v místě hlavní větve -Můžete provádět testování, ujistit se, že hotfix splňuje všechny požadavky, a pak můžete větev začlenit (merge) zpět do hlavní větve, aby byla připravena do produkce. Učiníte tak příkazem `git merge`: +Můžete spustit testy, abyste se ujistili, že hotfix splňuje všechny požadavky, a pak můžete větev začlenit (merge) zpět do hlavní větve, aby byla připravena do produkce. Učiníte tak příkazem `git merge`: $ git checkout master $ git merge hotfix Updating f42c576..3a0874c - Fast forward - README | 1 - - 1 files changed, 0 insertions(+), 1 deletions(-) + Fast-forward + README | 1 - + 1 file changed, 1 deletion(-) Při sloučení jste si možná všimli spojení „Fast forward“ (rychle vpřed). Jelikož revize, na niž ukazovala větev, do níž jste začleňovali, byla v přímé linii s revizí, na níž jste se nacházeli, Git přesunul ukazatel vpřed. Jinými slovy: pokud se pokoušíte sloučit jednu revizi s revizí druhou, k níž lze dospět následováním historie první revize, Git proces zjednoduší a přesune ukazatel vpřed, protože neexistuje žádná rozdílná práce, kterou by bylo třeba sloučit. Tomuto postupu se říká „rychle vpřed“. @@ -177,21 +177,21 @@ Obrázek 3-14. Hlavní větev ukazuje po sloučení na stejné místo jako věte Poté, co jste dokončili práci na bezodkladné opravě, můžete přepnout zpět na práci, jíž jste se věnovali před telefonátem. Nejprve však smažete větev `hotfix`, kterou teď už nebudete potřebovat – větev `master` ukazuje na totéž místo. Větev smažete přidáním parametru `-d` k příkazu `git branch`: $ git branch -d hotfix - Deleted branch hotfix (3a0874c). + Deleted branch hotfix (was 3a0874c). Nyní můžete přepnout zpět na větev s rozdělanou prací a pokračovat na chybě č. 53 (viz obrázek 3-15): $ git checkout iss53 - Switched to branch "iss53" + Switched to branch 'iss53' $ vim index.html - $ git commit -a -m 'finished the new footer [issue 53]' - [iss53]: created ad82d7a: "finished the new footer [issue 53]" - 1 files changed, 1 insertions(+), 0 deletions(-) + $ git commit -a -m 'finish the new footer [issue 53]' + [iss53 ad82d7a] finish the new footer [issue 53] + 1 file changed, 1 insertion(+) Insert 18333fig0315.png Obrázek 3-15. Větev iss53 může nezávisle postupovat vpřed. -Za zmínku stojí, že práce, kterou jste udělali ve větvi `hotfix`, není obsažena v souborech ve větvi `iss53`. Pokud potřebujete tyto změny do větve natáhnout, můžete začlenit větev `master` do větve `iss53` – použijte příkaz `git merge master`. Druhou možností je s integrací změn vyčkat a provést ji až ve chvíli, kdy budete chtít větev `iss53` natáhnout zpět do větve `master`. +Za zmínku stojí, že práce, kterou jste udělali ve větvi `hotfix`, není obsažena v souborech ve větvi `iss53`. Pokud potřebujete tyto změny do větve vtáhnout, můžete začlenit větev `master` do větve `iss53` provedením příkazu `git merge master`. Druhou možností je s integrací změn vyčkat a provést ji až ve chvíli, kdy budete chtít větev `iss53` vtáhnout zpět do větve `master`. ### Základní slučování ### @@ -199,9 +199,10 @@ Předpokládejme, že jste dokončili práci na chybě č. 53 a nyní byste ji r $ git checkout master $ git merge iss53 - Merge made by recursive. - README | 1 + - 1 files changed, 1 insertions(+), 0 deletions(-) + Auto-merging README + Merge made by the 'recursive' strategy. + README | 1 + + 1 file changed, 1 insertion(+) Toto už se trochu liší od začlenění větve `hotfix`, které jste prováděli před chvílí. V tomto případě se historie vývoje od určitého bodu v minulosti rozbíhala. Vzhledem k tomu, že revize na větvi, na níž se nacházíte, není přímým předkem větve, kterou chcete začlenit, Git bude muset podniknout určité kroky. Git v tomto případě provádí jednoduché třícestné sloučení: vychází ze dvou snímků, na které ukazují větve, a jejich společného předka. Obrázek 3-16 označuje ony tři snímky, které Git v tomto případě použije ke sloučení. @@ -210,7 +211,7 @@ Obrázek 3-16. Git automaticky identifikuje nejvhodnějšího společného před Git tentokrát neposune ukazatel větve vpřed, ale vytvoří nový snímek jako výsledek tohoto třícestného sloučení a automaticky vytvoří novou revizi, která bude na snímek ukazovat (viz obrázek 3-17). Takové revizi se říká revize sloučením (merge commit) a její zvláštností je to, že má více než jednoho rodiče. -Na tomto místě bych chtěl zopakovat, že Git určuje nejvhodnějšího společného předka, který bude použit jako základna pro sloučení, automaticky. Liší se tím od systému CVS i Subversion (před verzí 1.5), kde musí vývojář při slučování najít nejvhodnější základnu pro sloučení sám. Slučování větví je tak v systému Git o poznání jednodušší než v těchto ostatních systémech. +Na tomto místě bych chtěl zopakovat, že Git určuje nejvhodnějšího společného předka, který bude použit jako základna pro sloučení, automaticky. Liší se tím od systému CVS i Subversion (před verzí 1.5), kde musí vývojář při slučování najít nejvhodnější základnu pro sloučení sám. Slučování větví je proto v systému Git o poznání jednodušší než v ostatních systémech. Insert 18333fig0317.png Obrázek 3-17. Git automaticky vytvoří nový objekt revize, který obsahuje sloučenou práci. @@ -230,25 +231,27 @@ Může se stát, že sloučení neproběhne bez problémů. Pokud jste tutéž Git nepřistoupil k automatickému vytvoření nové revize sloučením. Prozatím pozastavil celý proces do doby, než konflikt vyřešíte. Chcete-li kdykoli po konfliktu zjistit, které soubory zůstaly nesloučeny, spusťte příkaz `git status`: - [master*]$ git status - index.html: needs merge - # On branch master - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # (use "git checkout -- ..." to discard changes in working directory) - # - # unmerged: index.html - # + $ git status + On branch master + You have unmerged paths. + (fix conflicts and run "git commit") + + Unmerged paths: + (use "git add ..." to mark resolution) + + both modified: index.html + + no changes added to commit (use "git add" and/or "git commit -a") -Vše, co při sloučení kolidovalo a nebylo vyřešeno, je označeno jako „unmerged“ (nesloučeno). Git přidává ke kolidujícím souborům standardní poznámky o řešení konfliktů (conflict-resolution markers), takže je můžete ručně otevřít a konflikty vyřešit. Jedna část vašeho souboru bude vypadat zhruba takto: +Vše, co při sloučení kolidovalo a nebylo vyřešeno, je označeno jako „unmerged“ (nesloučeno). Git přidává ke kolidujícím souborům standardní značky pro označení konfliktů (conflict-resolution markers), takže soubor můžete ručně otevřít a konflikty vyřešit. Jedna část vašeho souboru bude vypadat zhruba takto: - <<<<<<< HEAD:index.html + <<<<<<< HEAD ======= - >>>>>>> iss53:index.html + >>>>>>> iss53 To znamená, že verze ve větvi s ukazatelem HEAD (vaše hlavní větev – v té jste se nacházeli při provádění příkazu merge) je uvedena v horní části tohoto bloku (všechno nad oddělovačem `=======`), verze obsažená ve větvi `iss53` je vše, co se nachází v dolní části. Chcete-li vzniklý konflikt vyřešit, musíte buď vybrat jednu z obou stran, nebo konflikt sloučit sami. Tento konflikt můžete vyřešit například nahrazením celého bloku tímto textem: @@ -260,12 +263,17 @@ Toto řešení obsahuje trochu z každé části a zcela jsem odstranil řádky Chcete-li k vyřešení problémů použít grafický nástroj, můžete spustit příkaz `git mergetool`, kterým otevřete příslušný vizuální nástroj pro slučování, a ten vás všemi konflikty provede: $ git mergetool - merge tool candidates: kdiff3 tkdiff xxdiff meld gvimdiff opendiff emerge vimdiff - Merging the files: index.html + + This message is displayed because 'merge.tool' is not configured. + See 'git mergetool --tool-help' or 'git help config' for more details. + 'git mergetool' will now attempt to use one of the following tools: + opendiff kdiff3 tkdiff xxdiff meld tortoisemerge gvimdiff diffuse diffmerge ecmerge p4merge araxis bc3 codecompare vimdiff emerge + Merging: + index.html Normal merge conflict for 'index.html': - {local}: modified - {remote}: modified + {local}: modified file + {remote}: modified file Hit return to start merge resolution tool (opendiff): Chcete-li použít jiný než výchozí nástroj pro slučování (Git mi v tomto případě vybral `opendiff`, protože jsem příkaz zadal v systému Mac), všechny podporované nástroje jsou uvedeny na začátku výstupu v části „merge tool candidates“ (možné nástroje pro slučování). Zadejte název nástroje, který chcete použít. V kapitole 7 probereme, jak lze tuto výchozí hodnotu pro vaše prostředí změnit. @@ -275,12 +283,12 @@ Až nástroj pro slučování zavřete, Git se vás zeptá, zda sloučení prob Ještě jednou můžete spustit příkaz `git status`, abyste si ověřili, že byly všechny konflikty vyřešeny: $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # modified: index.html - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: index.html + Pokud jste s výsledkem spokojeni a ujistili jste se, že všechny kolidující soubory jsou připraveny k zapsání, můžete zadat příkaz `git commit` a dokončit revizi sloučením. Zpráva revize má v takovém případě přednastavenu tuto podobu: @@ -289,9 +297,9 @@ Pokud jste s výsledkem spokojeni a ujistili jste se, že všechny kolidující Conflicts: index.html # - # It looks like you may be committing a MERGE. + # It looks like you may be committing a merge. # If this is not correct, please remove the file - # .git/MERGE_HEAD + # .git/MERGE_HEAD # and try again. # @@ -331,7 +339,7 @@ Chcete-li zobrazit větve, které obsahují dosud nezačleněnou práci, spusťt Nyní se zobrazila jiná větev. Jelikož obsahuje práci, která ještě nebyla začleněna, bude pokus o její smazání příkazem `git branch -d` neúspěšný: $ git branch -d testing - error: The branch 'testing' is not an ancestor of your current HEAD. + error: The branch 'testing' is not fully merged. If you are sure you want to delete it, run 'git branch -D testing'. Pokud chcete větev skutečně odstranit a zahodit práci, kterou obsahuje, můžete si to vynutit parametrem `-D` (jak napovídá užitečná zpráva pod řádkem s chybovým hlášením). @@ -344,7 +352,7 @@ Teď, když jste absolvovali základní seznámení s větvemi a jejich slučov Vzhledem k tomu, že Git používá jednoduché třícestné slučování, je velmi snadné začleňovat jednu větev do druhé i několikrát v rámci dlouhého časového intervalu. Můžete tak mít několik větví, které jsou stále otevřené a které používáte pro různé fáze vývojového cyklu. Pravidelně můžete začleňovat práci z jedné větve do ostatních. -Mnoho vývojářů systému Git používá pracovní postup, při němž je tato metoda zcela ideální. Ve větvi `master` mají pouze kód, který je stoprocentně stabilní — třeba jen kód, který byl nebo bude součástí vydání. Kromě ní mají další paralelní větev, pojmenovanou `develop` nebo `next`, v níž skutečně pracují nebo testují stabilitu kódu. Tato větev nemusí být nutně stabilní, ale jakmile se dostane do stabilního stavu, může být začleněna do větve `master`. Používá se k natahování tematických větví (těch dočasných, jako byla vaše větev `iss53`) ve chvíli, kdy je k tomu vše připraveno a nehrozí, že práce neprojde testy nebo bude způsobovat chyby. +Mnoho vývojářů systému Git používá pracovní postup, kdy mají ve větvi `master` pouze kód, který je stoprocentně stabilní — třeba jen kód, který byl nebo bude součástí vydání. Kromě ní mají další paralelní větev, pojmenovanou `develop` nebo `next`, v níž skutečně pracují nebo testují stabilitu kódu. Tato větev nemusí být nutně stabilní, ale jakmile se dostane do stabilního stavu, může být začleněna do větve `master`. Do ní se vtahují tématické větve (ty dočasné, jako byla vaše větev `iss53`) ve chvíli, kdy jsou připravené a je jisté, že projdou všemi testy a nezavlečou chyby. Ve skutečnosti hovoříme o ukazatelích pohybujících se vzhůru po linii revizí, které zapisujete. Stabilní větve leží v linii historie revizí níže a nové, neověřené větve se nacházejí nad nimi (viz obrázek 3-18). @@ -361,11 +369,11 @@ Není nutné používat při práci několik dlouhých větví, ale často to m ### Tematické větve ### -Naproti tomu tematické větve se vám budou hodit v projektech jakékoli velikosti. Tematická větev (topic branch) je krátkodobá větev, kterou vytvoříte a používáte pro jediný konkrétní účel nebo práci. Je to záležitost, do které byste se ve VCS asi raději nikdy nepustili, protože vytvářet a slučovat větve je v něm opravdu složité. V systému Git naopak není výjimkou vytvářet, používat, slučovat a mazat větve i několikrát denně. +Naproti tomu tematické větve se vám budou hodit v projektech jakékoli velikosti. Tematická větev (topic branch) je krátkodobá větev, kterou vytvoříte a používáte pro jediný konkrétní účel nebo práci. Je to záležitost, do které byste se v jiném systému pro správu verzí asi raději nikdy nepustili, protože vytvářet a slučovat větve je v něm opravdu složité. V systému Git naopak není výjimkou vytvářet, používat, slučovat a mazat větve i několikrát denně. -Viděli jste to v předchozí části, kdy jste si vytvořili větve `iss53` a `hotfix`. Provedli jste v nich pár revizí a smazali jste je hned po začlenění změn do hlavní větve. Tato technika umožňuje rychlé a kompletní kontextové přepínání. Protože je vaše práce rozdělena do zásobníků, kde všechny změny v jedné větvi souvisí s jedním tématem, je při kontrole kódu snazší dohledat, čeho se změny týkaly apod. Změny tu můžete uchovávat několik minut, dní i měsíců a začlenit je přesně ve vhodnou chvíli. Na pořadí, v jakém byly větve vytvořeny nebo vyvíjeny, nezáleží. +Viděli jste to v předchozí části, kdy jste si vytvořili větve `iss53` a `hotfix`. Provedli jste v nich pár revizí a smazali jste je hned po začlenění změn do hlavní větve. Tato technika umožňuje rychlé a snadné kontextové přepínání. Protože je vaše práce rozdělena do zásobníků, kde všechny změny v jedné větvi souvisí s jedním tématem, je při kontrole kódu snazší dohledat, čeho se změny týkaly apod. Změny tu můžete uchovávat několik minut, dní i měsíců a začlenit je přesně ve vhodnou chvíli. Na pořadí, v jakém byly větve vytvořeny nebo vyvíjeny, nezáleží. -Uvažujme nyní následující situaci: pracujete na projektu v hlavní větvi (`master`), odbočíte z ní k vyřešení jednoho problému (`iss91`), chvíli na něm pracujete, ale vytvoříte ještě další větev, abyste zkusili jiné řešení stejné chyby (`iss91v2`). Pak se vrátíte zpět na hlavní větev, kde pokračujete v práci, než dostanete nápad, který by se možná mohl osvědčit, a tak pro něj vytvoříte další větev (`dumbidea`). Historie revizí bude vypadat zhruba jako na obrázku 3-20. +Uvažujme nyní následující situaci: pracujete na projektu v hlavní větvi (`master`), odvětvíme se z ní k vyřešení jednoho problému (`iss91`), chvíli na něm pracujete, ale vytvoříte ještě další větev, abyste zkusili jiné řešení stejné chyby (`iss91v2`). Pak se vrátíte zpět do hlavní větve, kde pokračujete v práci, a pak dostanete nápad, který by se možná mohl osvědčit, a tak pro něj vytvoříte další větev (`dumbidea`). Historie revizí bude vypadat zhruba jako na obrázku 3-20. Insert 18333fig0320.png Obrázek 3-20. Historie revizí s několika tematickými větvemi @@ -381,7 +389,7 @@ Při tom všem, co nyní děláte, je důležité mít na paměti, že všechny Vzdálené větve jsou reference (tj. odkazy) na stav větví ve vašich vzdálených repozitářích. Jsou to lokální větve, které nemůžete přesouvat. Přesouvají se automaticky při síťové komunikaci. Vzdálené větve slouží jako záložky, které vám připomínají, kde byly větve ve vzdálených repozitářích, když jste se k nim naposledy připojili. -Vzdálené větve mají podobu `(vzdálený repozitář)/(větev)`. Například: Chcete-li zjistit, jak vypadala větev `master` na vašem vzdáleném serveru `origin`, když jste s ní naposledy komunikovali, budete hledat větev `origin/master`. Pokud pracujete s kolegou na stejném problému a on odešle na server větev s názvem `iss53`, může se stát, že i vy máte jednu z lokálních větví pojmenovanou jako `iss53`. Větev na serveru však ukazuje na revizi označenou jako `origin/iss53`. +Vzdálené větve mají podobu `(vzdálený repozitář)/(větev)`. Pokud například chcete zjistit, jak vypadala větev `master` na vašem vzdáleném serveru `origin`, když jste s ní naposledy komunikovali, budete hledat větev `origin/master`. Pokud pracujete s kolegou na stejném problému a on odešle na server větev s názvem `iss53`, může se stát, že i vy máte jednu z lokálních větví pojmenovanou jako `iss53`. Větev na serveru však ukazuje na revizi označenou jako `origin/iss53`. Mohlo by to být trochu matoucí, takže si uveďme příklad. Řekněme, že máte v síti server Git označený `git.ourcompany.com`. Pokud provedete klonování z tohoto serveru, Git ho automaticky pojmenuje `origin`, stáhne z něj všechna data, vytvoří ukazatel, který bude označovat jeho větev `master`, a lokálně ji pojmenuje `origin/master`. Tuto větev nemůžete přesouvat. Git vám rovněž vytvoří vaši vlastní větev `master`, která bude začínat ve stejném místě jako větev `master` serveru `origin`. Máte tak definován výchozí bod pro svoji práci (viz obrázek 3-22). @@ -393,10 +401,10 @@ Pokud nyní budete pracovat na své lokální hlavní větvi a někdo z kolegů Insert 18333fig0323.png Obrázek 3-23. Pokud pracujete lokálně a někdo jiný odešle svou práci na vzdálený server, obě historie se rozejdou. -K synchronizaci své práce použijte příkaz `git fetch origin`. Tento příkaz zjistí, který server je „origin“ (v našem případě je to `git.ourcompany.com`), vyzvedne z něj všechna data, která ještě nemáte, a aktualizuje vaši lokální databázi. Při tom přemístí ukazatel `origin/master` na novou, aktuálnější pozici (viz obrázek 3-24). +K synchronizaci své práce použijte příkaz `git fetch origin`. Tento příkaz zjistí, který server je `origin` (v našem případě je to `git.ourcompany.com`), vyzvedne z něj všechna data, která ještě nemáte, a aktualizuje vaši lokální databázi. Při tom přemístí ukazatel `origin/master` na novou, aktuálnější pozici (viz obrázek 3-24). Insert 18333fig0324.png -Obrázek 3-24. Příkaz git fetch aktualizuje vaše reference na vzdálený server. +Obrázek 3-24. Příkaz `git fetch` aktualizuje vaše reference na vzdálený server. Abychom si mohli ukázat, jak se pracuje s několika vzdálenými servery a jak vypadají vzdálené větve takových vzdálených projektů, předpokládejme, že máte ještě další interní server Git, který při vývoji používá pouze jeden z vašich sprint teamů. Tento server se nachází na `git.team1.ourcompany.com`. Můžete ho přidat jako novou vzdálenou referenci k projektu, na němž právě pracujete – spusťte příkaz `git remote add` (viz kapitola 2). Pojmenujte tento vzdálený server jako `teamone`, což bude zkrácený název pro celou URL adresu (viz obrázek 3-25). @@ -439,28 +447,28 @@ Tady je důležité upozornit, že pokud vyzvedáváte data a stáhnete s nimi i Chcete-li začlenit tato data do své aktuální pracovní větve, spusťte příkaz `git merge origin/serverfix`. Chcete-li mít vlastní větev `serverfix`, na níž budete pracovat, můžete ji ze vzdálené větve vyvázat: $ git checkout -b serverfix origin/serverfix - Branch serverfix set up to track remote branch refs/remotes/origin/serverfix. - Switched to a new branch "serverfix" + Branch serverfix set up to track remote branch serverfix from origin. + Switched to a new branch 'serverfix' Tímto způsobem získáte lokální větev, na níž můžete pracovat a která začíná na pozici `origin/serverfix`. ### Sledující větve ### -Checkoutem lokální větve ze vzdálené větve automaticky vytvoříte tzv. Sledující větev (angl. tracking branch). Sledující větve jsou lokální větve s přímým vztahem ke vzdálené větvi. Pokud se nacházíte na Sledující větvi a zadáte příkaz `git push`, Git automaticky ví, na který server a do které větve má data odeslat. Také příkazem `git pull` zadaným na sledovací větvi vyzvednete všechny vzdálené reference a Git poté odpovídající vzdálenou větev automaticky začlení. +Checkoutem lokální větve ze vzdálené větve automaticky vytvoříte takzvanou *sledující větev* (angl. tracking branch). Sledující větve jsou lokální větve s přímým vztahem ke vzdálené větvi. Pokud se nacházíte na sledující větvi a zadáte příkaz `git push`, Git automaticky ví, na který server a do které větve má data odeslat. Také příkazem `git pull` zadaným na sledovací větvi vyzvednete všechny vzdálené reference a Git poté odpovídající vzdálenou větev automaticky začlení. -Pokud klonujete repozitář, většinou se vytvoří větev `master`, která bude sledovat větev `origin/master`. To je také důvod, proč příkazy `git push` a `git pull` fungují i bez dalších parametrů. Pokud chcete, můžete nastavit i jiné sledující větve – takové, které nebudou sledovat větve na serveru `origin` a nebudou sledovat hlavní větev `master`. Jednoduchým případem je příklad, který jste právě viděli: spuštění příkazu `git checkout -b [větev] [vzdálený server]/[větev]`. Máte-li Git ve verzi 1.6.2 nebo novější, můžete použít také zkrácenou variantu `--track`: +Pokud klonujete repozitář, většinou se vytvoří větev `master`, která bude sledovat větev `origin/master`. To je také důvod, proč příkazy `git push` a `git pull` fungují samy od sebe i bez dalších parametrů. Pokud chcete, můžete nastavit i jiné sledující větve – takové, které nebudou sledovat větve na serveru `origin` a nebudou sledovat hlavní větev `master`. Jednoduchým případem je příklad, který jste právě viděli: spuštění příkazu `git checkout -b [větev] [vzdálený server]/[větev]`. Máte-li Git ve verzi 1.6.2 nebo novější, můžete použít také zkrácenou variantu `--track`: $ git checkout --track origin/serverfix - Branch serverfix set up to track remote branch refs/remotes/origin/serverfix. - Switched to a new branch "serverfix" + Branch serverfix set up to track remote branch serverfix from origin. + Switched to a new branch 'serverfix' Chcete-li nastavit lokální větev s jiným názvem, než má vzdálená větev, můžete jednoduše použít první variantu s odlišným názvem lokální větve: $ git checkout -b sf origin/serverfix - Branch sf set up to track remote branch refs/remotes/origin/serverfix. - Switched to a new branch "sf" + Branch sf set up to track remote branch serverfix from origin. + Switched to a new branch 'sf' -Vaše lokální větev „sf“ bude nyní automaticky stahovat data ze vzdálené větve origin/serverfix a bude do ní i odesílat. +Vaše lokální větev `sf` bude nyní automaticky stahovat data ze vzdálené větve `origin/serverfix` a bude do ní i odesílat. ### Mazání vzdálených větví ### @@ -488,7 +496,7 @@ Víme, že nejjednodušším způsobem, jak integrovat větve, je příkaz `merg Insert 18333fig0328.png Obrázek 3-28. Integrace rozdělené historie sloučením větví -Existuje však ještě jiný způsob. Můžete vzít záplatu se změnou, kterou jste provedli revizí C3, a aplikovat ji na vrcholu revize C4. V systému Git se tato metoda nazývá přeskládání (rebasing). Příkazem `rebase` vezmete všechny změny, které byly zapsány na jedné větvi, a necháte je znovu provést na jiné větvi. +Existuje však ještě jiný způsob. Můžete vzít záplatu se změnou, kterou jste provedli revizí C3, a aplikovat ji na vrcholu revize C4. V systému Git se tato metoda nazývá *přeskládání* (rebasing). Příkazem `rebase` vezmete všechny změny, které byly zapsány na jedné větvi, a necháte je znovu provést na jiné větvi. V našem případě tedy provedete následující: @@ -507,7 +515,7 @@ Nyní můžete přejít zpět na hlavní větev a provést sloučení „rychle Insert 18333fig0330.png Obrázek 3-30. „Rychle vpřed“ po hlavní větvi -Snímek, na který nyní ukazuje revize C3, je zcela totožný se snímkem, na který v příkladu v části o slučování ukazovala C5. V koncových produktech integrace není žádný rozdíl, výsledkem přeskládání je však čistší historie. Pokud si prohlížíte log přeskládané větve, vypadá jako lineární historie – zdá se, jako by veškerá práce probíhala v jedné linii, ačkoli původně byla paralelní. +Snímek, na který nyní ukazuje revize C3', je zcela totožný se snímkem, na který v příkladu v části o slučování ukazovala C5. V koncových produktech integrace není žádný rozdíl, výsledkem přeskládání je však čistší historie. Pokud si prohlížíte log přeskládané větve, vypadá jako lineární historie – zdá se, jako by veškerá práce probíhala v jedné linii, ačkoli původně byla paralelní. Tuto metodu budete často používat v situaci, kdy chcete mít jistotu, že byly vaše revize čistě aplikovány na vzdálenou větev – např. v projektu, do nějž chcete přidat příspěvek, který ale nespravujete. V takovém případě budete pracovat ve své větvi, a až budete mít připraveny záplaty k odeslání do hlavního projektu, přeskládáte svou práci na větev `origin/master`. Správce v tomto případě nemusí provádět žádnou integraci, provede pouze posun „rychle vpřed“ nebo čistou aplikaci. @@ -537,7 +545,7 @@ Nyní můžete posunout hlavní větev „rychle vpřed“ (viz obrázek 3-33): Insert 18333fig0333.png Obrázek 3-33. Posun hlavní větve rychle vpřed na konec změn přeskládaných z větve client -Řekněme, že se později rozhodnete natáhnout i větev server. Větev server můžete přeskládat na hlavní větev příkazem `git rebase [základna] [tematická větev]`. Příkaz provede checkout tematické větve (v tomto případě větve `server`) a přeskládá její změny na základnu (angl. base branch, v tomto případě `master`): +Řekněme, že se později rozhodnete vtáhnout i větev server. Větev server můžete přeskládat na hlavní větev příkazem `git rebase [základna] [tematická větev]`. Příkaz provede checkout tematické větve (v tomto případě větve `server`) a přeskládá její změny na základnu (angl. base branch, v tomto případě `master`): $ git rebase master server @@ -563,9 +571,9 @@ Obrázek 3-35. Konečná historie revizí Přeskládání sice nabízí určité výhody, má však také svá úskalí. Ta se dají shrnout do jedné věty: -Neprovádějte přeskládání u revizí, které jste odeslali do veřejného repozitáře. +**Neprovádějte přeskládání u revizí, které jste odeslali do veřejného repozitáře.** -Budete-li se touto zásadou řídit, nemusíte se přeskládání obávat. V opačném případě vás čeká opovržení ostatních, rodina a přátelé vás zapřou. +Budete-li se touto zásadou řídit, nemusíte se přeskládání obávat. V opačném případě vás čeká nenávist ostatních a rodina a přátelé vás zavrhnou. Při přeskládání dat zahodíte existující revize a vytvoříte nové, které jsou jim podobné, ale přesto jiné. Pokud odešlete svou práci, ostatní si ji stáhnou a založí na nich svou práci. A vy potom tyto revize přepíšete příkazem `git rebase` a znovu je odešlete, vaši spolupracovníci do ní budou muset znovu začlenit svou práci a ve všem nastane chaos, až se pokusíte natáhnout jejich práci zpět do své. diff --git a/cs/04-git-server/01-chapter4.markdown b/cs/04-git-server/01-chapter4.markdown index 746caa912..3dd7abd9b 100644 --- a/cs/04-git-server/01-chapter4.markdown +++ b/cs/04-git-server/01-chapter4.markdown @@ -1,22 +1,22 @@ # Git na serveru # -V této chvíli byste už měli zvládat většinu každodenních úkonů, pro něž se vyplatí Git používat. Abyste však mohli v systému Git spolupracovat s ostatními, budete potřebovat vzdálený repozitář Git. Technicky vzato sice můžete odesílat a stahovat změny z repozitářů jednotlivých spolupracovníků, tento postup ale nedoporučujeme, protože se může při troše neopatrnosti velmi snadno stát, že zapomenete, kdo na čem pracuje. Navíc chcete, aby měli vaši spolupracovníci do repozitáře přístup, i když je váš počítač offline – na společný repozitář bývá často lepší spolehnutí. Jako nejlepší metodu spolupráce s ostatními proto můžeme doporučit nastavení „neutrálního“ repozitáře, do nějž budete mít všichni přístup, budete do něj moci odesílat data a budete z něj moci stahovat. Tomuto repozitáři budeme říkat „server Git“. Jak ale zjistíte, nebývá hostování repozitáře Git nijak zvlášť náročné na zdroje, a tak nejspíš nebudete potřebovat celý server. +V této chvíli byste už měli zvládat většinu každodenních úkonů, pro něž se vyplatí Git používat. Abyste však mohli v systému Git spolupracovat s ostatními, budete potřebovat vzdálený repozitář Git. Technicky vzato sice můžete odesílat a stahovat změny z repozitářů jednotlivých spolupracovníků, tento postup ale nedoporučujeme, protože se může při troše neopatrnosti velmi snadno stát, že zapomenete, kdo na čem pracuje. Navíc chcete, aby měli vaši spolupracovníci do repozitáře přístup, i když je váš počítač vypnutý nebo odpojený – na společný repozitář bývá často lepší spolehnutí. Jako nejlepší metodu spolupráce s ostatními proto můžeme doporučit nastavení „neutrálního“ repozitáře, do nějž budete mít všichni přístup, budete do něj moci odesílat data a budete z něj moci stahovat. Tomuto repozitáři budeme říkat „gitový server“. Jak ale zjistíte, nebývá hostování gitového repozitáře nijak zvlášť náročné na zdroje, a tak nejspíš nebudete potřebovat celý server. -Spuštění serveru Git je jednoduché. Nejprve určíte, jakými protokoly má váš server komunikovat. První část této kapitoly se bude věnovat možným protokolům, jejich přednostem a nevýhodám. V dalších částech popíšeme některá typická nastavení pro použití těchto protokolů, a jak s nimi uvést server do provozu. Nakonec se podíváme na několik možností hostování pro případ, že nebudete mít chuť podstupovat martyrium s nastavováním a správou vlastního serveru a nevadí vám umístit svůj kód na cizí server. +Zprovoznění gitového serveru je jednoduché. Nejprve určíte, jakými protokoly má váš server komunikovat. První část této kapitoly se bude věnovat možným protokolům, jejich přednostem a nevýhodám. V dalších částech popíšeme některá typická nastavení pro použití těchto protokolů, a jak s nimi uvést server do provozu. Nakonec se podíváme na několik možností hostování pro případ, že nebudete mít chuť podstupovat martyrium s nastavováním a správou vlastního serveru a nevadí vám umístit svůj kód na cizí server. -Pokud víte, že nebudete chtít spravovat vlastní server, můžete přeskočit rovnou na poslední část této kapitoly a podívat se na možnosti nastavení hostovaného účtu. Pak přejděte na následující kapitolu, v níž se dočtete o různých vstupech a výstupech při práci v prostředí s distribuovanou správou zdrojového kódu. +Pokud víte, že nebudete chtít spravovat vlastní server, můžete přeskočit rovnou na poslední část této kapitoly a podívat se na možnosti nastavení hostovaného účtu. Pak přejděte na následující kapitolu, v níž se dočtete o detailech a záludnostech při práci v prostředí s distribuovanou správou zdrojového kódu. -Vzdálený repozitář je obvykle holý repozitář, tj. repozitář Git bez pracovního adresáře. Protože se repozitář používá pouze jako místo pro spolupráci, není žádný důvod, aby byl na disku načten konkrétní snímek. Jsou tu pouze uložena data systému Git. Jednoduše bychom mohli také říct, že holý repozitář je obsah adresáře `.git` vašeho projektu a nic víc. +Vzdálený repozitář je obvykle *holý repozitář* (bare repository), tj. gitový repozitář bez pracovního adresáře. Protože se repozitář používá pouze jako místo pro spolupráci, není žádný důvod, aby byl na disku načten konkrétní snímek. Jsou tu pouze uložena data systému Git. Jednoduše bychom mohli také říct, že holý repozitář je obsah adresáře `.git` vašeho projektu a nic víc. ## Protokoly ## Git může k přenosu dat používat jeden ze čtyř hlavních síťových protokolů: Local, Secure Shell (SSH), Git nebo HTTP. V této části se podíváme na to, co jsou jednotlivé protokoly zač a za jakých okolností je (ne)vhodné je použít. -Neměli bychom zamlčet ani to, že s výjimkou protokolu HTTP všechny vyžadují, aby byl na serveru nainstalován a spuštěn systém Git. +Neměli bychom zamlčet ani to, že s výjimkou protokolu HTTP všechny vyžadují, aby byl na serveru nainstalován a zprovozněn systém Git. -### Protokol Local ### +### Lokální protokol ### -Nejzákladnější variantou je protokol Local, v němž je vzdálený repozitář uložen v jiném adresáři na disku. Často se využívá v případech, kdy mají všichni z vašeho týmu přístup k vašim sdíleným souborům, např. přes připojení systému NFS, nebo – v méně pravděpodobném případě – se všichni přihlašují na jednom počítači. Tato druhá varianta není právě ideální, protože všechny instance repozitáře s kódem jsou v takovém případě umístěny v jednom počítači, čímž se zvyšuje riziko nevratné ztráty dat. +Nejzákladnější variantou je *lokální protokol* (Local protocol), v němž je vzdálený repozitář uložen v jiném adresáři na disku. Často se využívá v případech, kdy mají všichni z vašeho týmu přístup k vašim sdíleným souborům, např. přes připojení systému NFS, nebo – v méně pravděpodobném případě – se všichni přihlašují na jednom počítači. Tato druhá varianta není právě ideální, protože všechny instance repozitáře s kódem jsou v takovém případě umístěny v jednom počítači, čímž se zvyšuje riziko nevratné ztráty dat. Máte-li připojený sdílený systém souborů, můžete klonovat, odesílat a stahovat z lokálního souborového repozitáře (local file-based repository). Chcete-li takový repozitář naklonovat nebo přidat jako vzdálený repozitář do existujícího projektu, použijte jako URL cestu k repozitáři. K naklonování lokálního repozitáře můžete použít příkaz například v tomto tvaru: @@ -26,7 +26,7 @@ Nebo můžete provést následující: $ git clone file:///opt/git/project.git -Pokud na začátek URL explicitně zadáte výraz `file://`, pracuje Git trochu jinak. Pokud pouze zadáte cestu, Git se pokusí použít hardlinky nebo rovnou zkopírovat soubory, které potřebuje. Pokud zadáte výraz `file://`, Git spustí procesy, jež běžně používá k přenosu dat prostřednictvím sítě. Síť je většinou výrazně méně výkonnou metodou přenosu dat. Hlavním důvodem, proč zadat předponu `file://` je to, že tak získáte čistou kopii repozitáře bez nepotřebných referencí a objektů, např. po importu z jiného verzovacího systému a podobně (úkony správy jsou popsány v kapitole 9). My budeme používat normální cestu, neboť tato metoda je téměř vždy rychlejší. +Pokud na začátek URL explicitně zadáte výraz `file://`, pracuje Git trochu jinak. Pokud pouze zadáte cestu a zdroj i cíl se nacházejí ve stejném systému souborů, pokusí se Git použít hardlinky na potřebné objekty. Pokud se nenacházejí ve stejném systému souborů, dojde k okopírování potřebných objektů pomocí standardních prostředků systému pro kopírování. Pokud zadáte výraz `file://`, Git spustí procesy, jež běžně používá k přenosu dat prostřednictvím sítě. Síť je většinou výrazně méně výkonnou metodou přenosu dat. Hlavním důvodem, proč zadat předponu `file://` je to, že tak získáte čistou kopii repozitáře bez nepotřebných referencí a objektů, například po importu z jiného verzovacího systému a podobně (úkony správy jsou popsány v kapitole 9). My budeme používat normální cestu, neboť tato metoda je téměř vždy rychlejší. K přidání lokálního repozitáře do existujícího projektu Git můžete použít příkaz například v tomto tvaru: @@ -44,17 +44,17 @@ Jedná se také o výbornou možnost, jak rychle získat práci z pracovního re Nevýhodou této metody je, že nastavit a získat sdílený přístup z více umístění je většinou těžší než obyčejný síťový přístup. Budete-li chtít pracovat doma a odeslat data z notebooku, budete muset připojit vzdálený disk, což může být ve srovnání s přístupem prostřednictvím sítě složité a pomalé. -Zapomenout bychom neměli ani na to, že používáte-li sdílené připojení určitého druhu, nemusí být tato možnost vždy nutně nejrychlejší. Lokální repozitář je rychlý pouze v případě, že máte rychlý přístup k datům. Repozitář na NFS je často pomalejší než repozitář nad SSH na tomtéž serveru, který ve všech systémech umožňuje spustit Git z lokálních disků. +Zapomenout bychom neměli ani na to, že používáte-li sdílené připojení určitého druhu, nemusí být tato možnost vždy nutně nejrychlejší. Lokální repozitář je rychlý pouze v případě, že máte rychlý přístup k datům. Repozitář na NFS je často pomalejší než stejný repozitář nad SSH na tomtéž serveru, který ve všech systémech umožňuje spustit Git z lokálních disků. ### Protokol SSH ### -Patrně nejčastějším přenosovým protokolem pro systém Git je SSH. Je to z toho důvodu, že SSH přístup k serverům je na většině míst už nastaven, a pokud ne, není ho těžké nastavit. SSH je navíc jediným síťovým protokolem, z nějž lze snadno číst a do nějž lze snadno zapisovat. Oba zbývající síťové protokoly (HTTP i Git) jsou většinou určeny pouze ke čtení, a proto i když je máte k dispozici, budete potřebovat SSH protokol pro příkazy k zápisu. SSH je také síťovým protokolem s ověřováním, a protože je hojně rozšířen, je jeho nastavení a používání většinou snadné. +Patrně nejčastějším přenosovým protokolem pro systém Git je SSH. Je to z toho důvodu, že SSH přístup k serverům je na většině míst už nastaven, a pokud ne, není ho těžké nastavit. SSH je navíc jediným síťovým protokolem, z nějž lze snadno číst a do nějž lze snadno zapisovat. Oba zbývající síťové protokoly (HTTP i Git) jsou většinou určeny pouze ke čtení, a proto i když je dáváte k dispozici ostatním, pro sebe budete potřebovat SSH protokol pro příkazy zápisu. SSH je také síťovým protokolem s autentizací, a protože je hojně rozšířen, je jeho nastavení a používání většinou snadné. -Chcete-li naklonovat repozitář Git pomocí protokolu SSH, zadejte „ssh:// URL“, například: +Chcete-li naklonovat repozitář Git pomocí protokolu SSH, zadejte `ssh://` URL, například: $ git clone ssh://user@server/project.git -Protokol ostatně ani nemusíte zadávat – pokud žádný výslovně neurčíte, Git použije SSH jako výchozí možnost: +Nebo můžete pro SSH protokol použít kratší zápis jako u scp: $ git clone user@server:project.git @@ -62,24 +62,24 @@ Stejně tak nemusíte zadávat ani uživatele, Git automaticky použije uživate #### Výhody #### -Používání protokolu SSH přináší mnoho výhod. Především byste ho měli používat vždy, když chcete v síti ověřovat oprávnění k zápisu do repozitáře. Zadruhé: protokol SSH má snadné nastavení – SSH démoni jsou zcela běžní, správci sítě si s nimi většinou vědí rady a mnoho distribucí OS je má ve výchozí instalaci nebo má nástroje, aby s nimi mohly pracovat. Z dalších výhod bychom měli zmínit také to, že přístup přes protokol SSH je bezpečný, veškerý přenos dat je šifrovaný a ověřený. A stejně jako protokoly Git a Local je i protokol SSH výkonný. Data jsou před přenosem upravena do co nejkompaktnější podoby. +Používání protokolu SSH přináší mnoho výhod. Především byste ho měli používat vždy, když chcete v síti používat autentizovaný zápis do repozitáře. Zadruhé: protokol SSH se snadno nastavuje – SSH démoni jsou zcela běžní, správci sítě si s nimi většinou vědí rady a mnoho distribucí OS je má ve výchozí instalaci nebo poskytuje nástroje pro jejich správu. Z dalších výhod bychom měli zmínit také to, že přístup přes protokol SSH je bezpečný, veškerý přenos dat je šifrovaný a autentizovaný. A stejně jako protokoly Git a Local je i protokol SSH výkonný, protože data jsou před přenosem upravena do co nejkompaktnější podoby. #### Nevýhody #### -Nevýhodou protokolu SSH je, že neumožňuje anonymní přístup do repozitáře. Chce-li někdo získat přístup do vašeho repozitáře, byť třeba jen ke čtení, musí mít přístup k vašemu počítači přes SSH. Proto se protokol SSH nehodí pro projekty s otevřeným zdrojovým kódem. Pokud repozitář používáte jen v rámci firemní sítě, bude pro vás protokol SSH zřejmě naprosto ideální. Pokud chcete povolit anonymní přístup pro čtení k vašim projektům, budete muset nastavit protokol SSH k odesílání svých dat, ale přidat jiný protokol, pomocí nějž budou ostatní tato data stahovat. +Nevýhodou protokolu SSH je, že neumožňuje anonymní přístup do repozitáře. Chce-li někdo získat přístup do vašeho repozitáře, byť třeba jen ke čtení, musí mít přístup k vašemu počítači přes SSH. Proto se protokol SSH nehodí pro projekty s otevřeným zdrojovým kódem. Pokud repozitář používáte jen v rámci firemní sítě, bude pro vás protokol SSH zřejmě naprosto ideální. Pokud chcete povolit anonymní přístup pro čtení k vašim projektům, budete muset nastavit protokol SSH k odesílání svých dat, ale musíte přidat i jiný protokol, který budou ostatní používat pro stahování. ### Protokol Git ### -Dalším protokolem v pořadí je protokol Git. Je to speciální démon, který je distribuován spolu se systémem Git. Naslouchá na vyhrazeném portu (9418) a poskytuje podobnou službu jako protokol SSH, avšak bez jakéhokoli ověřování. Chcete-li, aby byl repozitář obsluhován protokolem Git, musíte vytvořit soubor `git-export-daemon-ok` – démon nebude repozitář obsluhovat, dokud v něm tento soubor nebude. Žádné jiné zabezpečení k dispozici není. Repozitář Git je buď dostupný pro všechny a všichni z něj mohou klonovat, nebo dostupný není. To znamená, že se přes tento protokol nedají odesílat žádné revize. Možnost odesílání lze aktivovat, ale vzhledem k tomu, že protokol neumožňuje ověřování, aktivované odesílání znamená, že kdokoli na internetu, kdo najde URL vašeho projektu, do něj bude moci odesílat data. Tato možnost se však téměř nepoužívá. +Dalším protokolem v pořadí je protokol Git. Je to speciální démon, který je distribuován spolu se systémem Git. Naslouchá na vyhrazeném portu (9418) a poskytuje podobnou službu jako protokol SSH, avšak bez jakékoliv autentizace. Chcete-li, aby byl repozitář zpřístupněn protokolem Git, musíte vytvořit soubor `git-daemon-export-ok`. Bez tohoto souboru nebude repozitář démonem zpřístupněn. Žádné jiné zabezpečení ale k dispozici není. Repozitář Git je buď dostupný pro všechny a všichni z něj mohou klonovat, nebo dostupný není. To znamená, že se přes tento protokol nedají odesílat žádné revize. Možnost odesílání lze zapnout, ale vzhledem k tomu, že protokol neumožňuje autentizaci, aktivované odesílání znamená, že kdokoli na internetu, kdo najde URL vašeho projektu, do něj bude moci odesílat data. Je jasné, že to většinou nechcete. #### Výhody #### -Protokol Git je ze všech dostupných protokolů nejrychlejší. Potřebujete-li, aby protokol obsluhoval frekventovaný provoz u veřejného projektu nebo velmi velký projekt, u nějž není třeba ověřování identity uživatele ohledně oprávnění pro čtení, bude k obsluze nejvhodnější pravděpodobně právě démon Git. Používá stejný mechanismus přenosu dat jako protokol SSH, na rozdíl od něj ale není zpomalován šifrováním a ověřováním. +Protokol Git je ze všech dostupných protokolů nejrychlejší. Potřebujete-li, aby protokol obsluhoval frekventovaný provoz u veřejného projektu nebo velmi velký projekt, u nějž není třeba ověřování identity uživatele ohledně oprávnění pro čtení, bude k obsluze nejvhodnější pravděpodobně právě démon Git. Používá stejný mechanismus přenosu dat jako protokol SSH, na rozdíl od něj ale není zpomalován šifrováním a ověřováním identity (autentizací). #### Nevýhody #### -Nevýhodou protokolu Git je, že neprovádí ověřování. Většinou není žádoucí, aby protokol Git tvořil jediný přístup k vašemu projektu. Protokol Git většinou využijete v kombinaci s přístupem přes SSH. Protokol SSH bude nastaven pro několik málo vývojářů s oprávněním k zápisu (odesílání dat) a všichni ostatní budou používat `git://` pro přístup pouze ke čtení. -Pravděpodobně se také jedná o protokol s nejobtížnějším nastavením. Vyžaduje spuštění vlastního démona – na jeho nastavení se podíváme v části „Gitosis“ této kapitoly – a dále konfiguraci `xinetd` nebo podobnou, která také není právě jednoduchá. Vyžaduje rovněž povolení přístupu k portu 9418 skrz firewall. Tento port nepatří mezi standardní porty, které by firemní firewally vždy povolovaly. Velkými podnikovými firewally je tento málo rozšířený port většinou blokován. +Nevýhodou protokolu Git je, že neprovádí autentizaci. Většinou není žádoucí, aby protokol Git tvořil jediný přístup k vašemu projektu. Protokol Git většinou využijete v kombinaci s přístupem přes SSH. Protokol SSH bude nastaven pro několik málo vývojářů s oprávněním k zápisu (odesílání dat) a všichni ostatní budou používat `git://` pro přístup pouze ke čtení. +Pravděpodobně se také jedná o protokol s nejobtížnějším nastavením. Vyžaduje spuštění vlastního démona – na jeho nastavení se podíváme v části „Gitosis“ této kapitoly – a dále konfiguraci `xinetd` nebo podobnou, což není zrovna procházka růžovou zahradou. Vyžaduje rovněž povolení přístupu k portu 9418 skrz firewall. Tento port nepatří mezi standardní porty, které by firemní firewally vždy povolovaly. Velkými podnikovými firewally je tento málo rozšířený port většinou blokován. ### Protokol HTTP/S ### @@ -91,11 +91,11 @@ Na konec jsme si nechali protokol HTTP. Co je na protokolu HTTP nebo HTTPS sympa $ mv hooks/post-update.sample hooks/post-update $ chmod a+x hooks/post-update -A to je vše. Zásuvný modul `post-update`, který je standardně součástí systému Git, spustí příkaz `git update-server-info`, který zajistí správné vyzvedávání a klonování dat přes protokol HTTP. Tento příkaz se spustí, když do tohoto repozitáře odesíláte data přes protokol SSH. Ostatní mohou klonovat třeba takto: +A to je vše. Zásuvný modul `post-update`, který je standardně součástí systému Git, spustí příslušný příkaz (`git update-server-info`), který zajistí správné vyzvedávání a klonování dat přes protokol HTTP. Tento příkaz se spustí, když do tohoto repozitáře odesíláte data přes protokol SSH. Poté mohou ostatní klonovat třeba takto: $ git clone http://example.com/gitproject.git -V tomto konkrétním případě používáme cestu `/var/www/htdocs`, která je obvyklá u nastavení Apache, ale použít lze v podstatě jakýkoli webový server – stačí uložit holý repozitář do daného umístění. Data repozitáře Git jsou obsluhována jako obyčejné statické soubory (podrobnosti naleznete v kapitole 9). +V tomto konkrétním případě používáme cestu `/var/www/htdocs`, která je obvyklá u nastavení Apache, ale použít lze v podstatě jakýkoli statický webový server – stačí uložit holý repozitář do dané cesty. Data repozitáře Git jsou obsluhována jako obyčejné statické soubory (podrobnosti o přesném způsobu obsluhy naleznete v kapitole 9). Odesílat data do repozitáře Git je možné také přes protokol HTTP, avšak tento způsob není příliš rozšířený a vyžaduje nastavení komplexních požadavků protokolu WebDAV. Protože se tato možnost využívá zřídka, nebudeme se jí v této knize věnovat. Pokud vás zajímá používání protokolů HTTP k odesílání dat, více se o přípravě repozitáře k tomuto účelu dočtete na adrese: `http://www.kernel.org/pub/software/scm/git/docs/howto/setup-git-server-over-http.txt` (anglicky). Příjemným faktem na odesílání dat přes protokol HTTP je, že můžete použít jakýkoli server WebDAV i bez speciálních funkcí systému Git. Tuto možnost tak můžete využít, pokud váš poskytovatel webhostingu podporuje WebDAV pro zápis aktualizací na vaše webové stránky. @@ -103,23 +103,24 @@ Odesílat data do repozitáře Git je možné také přes protokol HTTP, avšak Pro používání protokolu HTTP mluví zejména jeho snadné nastavení. Vystačíte s několika málo příkazy, ale získáte jednoduchý způsob, jak nastavit oprávnění pro čtení repozitáře Git pro okolní svět. Celý postup nezabere víc než pár minut. Protokol HTTP navíc jen minimálně omezuje zdroje serveru. Vzhledem k tomu, že k obsluze všech dat používá většinou statický HTTP server, obslouží běžný server Apache průměrně několik tisíc souborů za sekundu. Ani malý server proto není snadné přetížit. -Své repozitáře můžete prostřednictvím protokolu HTTPS poskytovat pouze ke čtení a šifrovat přenos dat. Nebo můžete zajít ještě dál a vyžadovat, aby klienti používali konkrétní podepsané SSL certifikáty. Je pravda, že v takovém případě by už bylo jednodušší použít veřejné SSH klíče, ale ve vašem konkrétním případě může být použití podepsaných SSL certifikátů nebo jiné ověření identity na základě protokolu HTTP lepší metodou, jak zajistit přístup přes HTTPS pouze ke čtení. +Své repozitáře můžete zpřístupnit ke čtení prostřednictvím protokolu HTTPS, což znamená, že se přenášený obsah šifruje. Nebo můžete zajít ještě dál a vyžadovat, aby klienti používali konkrétní podepsané SSL certifikáty. Je pravda, že v takovém případě by už bylo jednodušší použít veřejné SSH klíče, ale ve vašem konkrétním případě může být použití podepsaných SSL certifikátů nebo jiné ověření identity na základě protokolu HTTP lepší metodou, jak zajistit přístup přes HTTPS pouze ke čtení. Z dalších výhod protokolu HTTP bychom mohli jmenovat i jeho značné rozšíření, díky čemuž jsou firemní firewally často nastaveny tak, že umožňují provoz přes standardní port protokolu HTTP. #### Nevýhody #### -Nevýhodou obsluhy repozitáře přes protokol HTTP je poměrně nízká výkonnost pro klienta. Klonovat nebo vyzvedávat data z repozitáře trvá v případě protokolu HTTP obecně mnohem déle a vyžádá si většinou podstatně větší režii síťových operací a objem přenášených dat, než je tomu u ostatních síťových protokolů. Protože protokol není natolik inteligentní, aby přenášel pouze data, která potřebujete – v těchto transakcích se na straně serveru nesetkáte s dynamickou činností – je protokol HTTP často nazýván „dumb protocol“ (hloupý protokol). Více informací o rozdílech ve výkonnosti mezi protokolem HTTP a ostatními protokoly najdete v kapitole 9. +Nevýhodou obsluhy repozitáře přes protokol HTTP je poměrně nízká výkonnost pro klienta. Klonovat nebo vyzvedávat data z repozitáře trvá v případě protokolu HTTP obecně mnohem déle a vyžádá si většinou podstatně větší režii síťových operací a objem přenášených dat, než je tomu u ostatních síťových protokolů. Protože protokol není natolik inteligentní, aby přenášel pouze data, která potřebujete – v těchto transakcích se na straně serveru nesetkáte s dynamickou činností – je protokol HTTP často nazýván *dumb protocol* (hloupý protokol). Více informací o rozdílech ve výkonnosti mezi protokolem HTTP a ostatními protokoly najdete v kapitole 9. ## Jak umístit Git na server ## Pro úvodní nastavení serveru Git je třeba exportovat existující repozitář do nového, holého repozitáře (bare repository), tj. do repozitáře, který neobsahuje pracovní adresář. S tím obvykle nebývá problém. -Chcete-li naklonovat stávající repozitář, a vytvořit tak nový a holý, zadejte příkaz clone s parametrem `--bare`. Je zvykem, že adresáře s holým repozitářem končí na `.git`, například: +Chcete-li naklonovat stávající repozitář, a vytvořit tak nový a holý, zadejte příkaz pro klonování s parametrem `--bare`. Je zvykem, že adresáře s holým repozitářem končí na `.git`, například: $ git clone --bare my_project my_project.git - Initialized empty Git repository in /opt/projects/my_project.git/ + Cloning into bare repository 'my_project.git'... + done. -Výstup tohoto příkazu je trochu nejasný. Protože příkaz `clone` znamená v podstatě `git init` a následně `git fetch`, vidíme z části `git init`, která vytvoří prázdný adresář, nějaký výstup. Následný přenos objektu neposkytuje žádný výstup, přesto však proběhl. V adresáři `my_project.git` byste nyní měli mít kopii dat z adresáře Git. +V adresáři `my_project.git` byste nyní měli mít kopii dat z adresáře Git. Je to přibližně stejné, jako byste zadali například: @@ -147,7 +148,7 @@ Vidíte, jak je jednoduché vzít repozitář Git, vytvořit jeho holou verzi a A to je skutečně vše, co je třeba ke spuštění serveru Git, k němuž bude mít přístup více lidí – na server stačí přidat SSH účty a umístit holý repozitář někam, kam budou mít všichni uživatelé oprávnění ke čtení i zápisu. Vše je připraveno, nic dalšího se od vás nevyžaduje. -V dalších částech se podíváme na některé pokročilé možnosti nastavení. Dozvíte se v nich, jak se vyhnout nutnosti vytvářet uživatelské účty pro všechny uživatele, jak k repozitářům přiřadit veřejné oprávnění pro čtení, jak nastavit webová rozhraní nebo k čemu se používá nástroj Gitosis. To však nemění nic na tom, že ke spolupráci se skupinou lidí na soukromém projektu vystačíte s jedním SSH serverem a holým repozitářem. +V dalších částech se podíváme na některé pokročilé možnosti nastavení. Dozvíte se v nich, jak se vyhnout nutnosti vytvářet uživatelské účty pro všechny uživatele, jak k repozitářům přiřadit veřejné oprávnění pro čtení, jak nastavit webová rozhraní nebo k čemu se používá nástroj Gitosis. To však nemění nic na tom, že ke spolupráci se skupinou lidí na soukromém projektu *vystačíte* s jedním SSH serverem a holým repozitářem. ### Nastavení pro malou skupinu ### @@ -157,9 +158,9 @@ Pokud provádíte nastavení jen pro malý okruh lidí nebo jen zkoušíte Git v Jestliže už máte server, k němuž mají všichni vaši vývojáři SSH přístup, bude většinou nejjednodušší nastavit první repozitář tam, protože celé nastavení už tím máte v podstatě hotové (jak jsme ukázali v předchozí části). Pokud chcete pro své repozitáře nastavit komplexnější správu oprávnění, můžete je opatřit běžnými oprávněními k systému souborů, které vám nabízí operační systém daného serveru. -Pokud chcete své repozitáře umístit na server, jenž nemá účty pro všechny členy vašeho týmu, kteří by měli mít oprávnění k zápisu, musíte pro ně nastavit SSH přístup. Předpokládáme, že pokud máte server, na němž to lze provést, máte už nainstalován server SSH. Tímto způsobem získáte přístup na server. +Pokud chcete své repozitáře umístit na server, jenž nemá účty pro všechny členy vašeho týmu, kteří by měli mít oprávnění k zápisu, musíte pro ně nastavit SSH přístup. Předpokládáme, že pokud máte server, na němž to lze provést, máte už nainstalován server SSH a jeho prostřednictvím k serveru přistupujete. -Existuje několik způsobů, jak umožnit přístup všem členům vašeho týmu. Prvním způsobem je nastavit účty pro všechny, což není složité, ale může být poněkud zdlouhavé. Možná nebudete mít chuť spouštět příkaz `adduser` (přidat uživatele) a nastavovat dočasná hesla pro každého uživatele zvlášť. +Existuje několik způsobů, jak umožnit přístup všem členům vašeho týmu. Prvním způsobem je nastavit účty pro všechny, což je sice přímočaré, ale může to být poněkud zdlouhavé. Možná nebudete mít chuť spouštět příkaz `adduser` (přidat uživatele) a nastavovat pro každého uživatele dočasná hesla. Druhým způsobem je vytvořit na počítači jediného uživatele 'git', požádat všechny uživatele, kteří mají mít oprávnění k zápisu, aby vám poslali veřejný SSH klíč, a přidat tento klíč do souboru `~/.ssh/authorized_keys` vašeho nového uživatele 'git'. Nyní budou mít všichni přístup k tomuto počítači prostřednictvím uživatele 'git'. Tento postup nemá žádný vliv na data vašich revizí – SSH uživatel, jehož účtem se přihlašujete, neovlivní revize, které jste nahráli. @@ -167,7 +168,7 @@ Dalším možným způsobem je nechat ověřovat SSH přístupy LDAP serveru neb ## Vygenerování veřejného SSH klíče ## -Mnoho serverů Git provádí ověřování pomocí veřejných SSH klíčů. Aby vám mohli všichni uživatelé ve vašem systému poskytnout veřejný klíč, musí si ho nechat vygenerovat (pokud klíč ještě nemají). Tento proces se napříč operačními systémy téměř neliší. +Mnoho serverů Git provádí ověřování totožnosti pomocí veřejných SSH klíčů. Aby vám mohli všichni uživatelé ve vašem systému poskytnout veřejný klíč, musí si ho každý z nich nechat vygenerovat (pokud klíč ještě nemá). Tento proces se napříč operačními systémy téměř neliší. Nejprve byste se měli ujistit, že ještě žádný klíč nemáte. Uživatelské SSH klíče jsou standardně uloženy v adresáři `~/.ssh` daného uživatele. Nejsnazší způsob kontroly, zda už klíč vlastníte, je přejít do tohoto adresáře a zjistit jeho obsah: $ cd ~/.ssh @@ -187,7 +188,7 @@ Zobrazí se několik souborů s názvem `xxx` a `xxx.pub`, kde `xxx` je většin The key fingerprint is: 43:c5:5b:5f:b1:f1:50:43:ad:20:a6:92:6a:1f:9a:3a schacon@agadorlaptop.local -Program nejprve potvrdí, kam chcete klíč uložit (`.ssh/id_rsa`), a poté se dvakrát zeptá na přístupové heslo. Pokud nechcete při používání klíče zadávat heslo, nemusíte ho nyní vyplňovat. +Program nejprve potvrdí, kam chcete klíč uložit (`.ssh/id_rsa`), a poté se dvakrát zeptá na přístupové heslo. Pokud nechcete při používání klíče zadávat heslo, můžete ho nyní nechat prázdné. Každý uživatel, který si tímto způsobem nechá vygenerovat veřejný klíč, ho nyní pošle vám nebo jinému správci serveru Git (za předpokladu, že používáte nastavení SSH serveru vyžadující veřejné klíče). Stačí přitom zkopírovat obsah souboru `.pub` a odeslat ho e-mailem. Veřejné klíče mají zhruba tuto podobu: @@ -203,7 +204,7 @@ Budete-li potřebovat podrobnější návod k vytvoření SSH klíče v různýc ## Nastavení serveru ## -Podívejme se nyní na nastavení SSH přístupu na straně serveru. V tomto příkladu použijeme k ověření uživatelů metodu `authorized_keys`. Předpokládáme také, že pracujete se standardní linuxovou distribucí, jako je např. Ubuntu. Nejprve vytvoříte uživatele 'git' a adresář `.ssh` pro tohoto uživatele. +Projděme si nastavení SSH přístupu na straně serveru. V tomto příkladu použijeme k ověření identity uživatelů metodu `authorized_keys`. Předpokládáme také, že pracujete se standardní linuxovou distribucí, jako je např. Ubuntu. Nejprve vytvoříte uživatele 'git' a adresář `.ssh` pro tohoto uživatele. $ sudo adduser git $ su git @@ -220,12 +221,16 @@ V dalším kroku musíte vložit veřejné SSH klíče od svých vývojářů do O7TCUSBdLQlgMVOFq1I2uPWQOkOWQAHukEOmfjy2jctxSDBQ220ymjaNsHT4kgtZg2AYYgPq dAv8JggJICUvax2T9va5 gsg-keypair -Vy nyní klíče vložíte do souboru `authorized_keys`: +Vy nyní klíče přidáte do souboru `authorized_keys`: $ cat /tmp/id_rsa.john.pub >> ~/.ssh/authorized_keys $ cat /tmp/id_rsa.josie.pub >> ~/.ssh/authorized_keys $ cat /tmp/id_rsa.jessica.pub >> ~/.ssh/authorized_keys +Autentizace vůči SSH, která je založená na klíči, obvykle vynucuje zvýšenou bezpečnost tím, že pro zúčastněné soubory vyžaduje omezená oprávnění. Aby SSH neodmítl pracovat, napište následující: + + $ chmod -R go= ~/.ssh + Nyní pro ně můžete nastavit prázdný repozitář. Spusťte příkaz `git init` s parametrem `--bare`, který inicializuje repozitář bez pracovního adresáře: $ cd /opt/git @@ -233,7 +238,7 @@ Nyní pro ně můžete nastavit prázdný repozitář. Spusťte příkaz `git in $ cd project.git $ git --bare init -John, Josie a Jessica pak mohou do tohoto repozitáře odeslat první verzi svého projektu: přidají si ho jako vzdálený repozitář a odešlou do něj svou větev. Nezapomeňte, že pokaždé, když chcete přidat projekt, se musí k počítači někdo přihlásit a vytvořit holý repozitář. Pro server, na kterém jste nastavili uživatele 'git' a repozitář, můžeme použít název hostitele `gitserver`. Pokud server provozujete interně a nastavíte DNS pro `gitserver` tak, aby ukazovalo na tento server, můžete používat i takovéto příkazy: +John, Josie a Jessica pak mohou do tohoto repozitáře odeslat první verzi svého projektu: přidají si ho jako vzdálený repozitář a odešlou do něj svou větev. Nezapomeňte, že pokaždé, když chcete vytvořit projekt, musí se k počítači někdo přihlásit a vytvořit holý repozitář. Pro server, na kterém jste nastavili uživatele 'git' a repozitář, můžeme použít název hostitele `gitserver`. Pokud server provozujete interně a nastavíte DNS pro `gitserver` tak, aby ukazovalo na tento server, můžete používat i takovéto příkazy: # on Johns computer $ cd myproject @@ -253,7 +258,7 @@ Ostatní nyní mohou velmi snadno repozitář naklonovat i do něj odesílat zm Tímto způsobem lze rychle vytvořit a spustit server Git ke čtení i zápisu pro menší počet vývojářů. -Pro větší bezpečnost máte možnost využít nástroj `git-shell`, který je distribuován se systémem Git. Pomocí něj lze snadno nastavit, aby uživatel 'git' prováděl pouze operace systému Git. Pokud ho nastavíte jako přihlašovací shell uživatele 'git', pak nebude mít uživatel 'git' normální shellový přístup k vašemu serveru. Chcete-li nástroj použít, zadejte pro přihlašovací shell vašeho uživatele `git-shell` místo bash nebo csh. V takovém případě pravděpodobně budete muset upravit soubor `/etc/passwd`: +Pro větší bezpečnost máte možnost využít nástroj `git-shell`, který je distribuován se systémem Git. Pomocí něj lze uživatele 'git' snadno omezit tak, aby mohl prováděl pouze operace systému Git. Pokud ho nastavíte jako přihlašovací shell uživatele 'git', pak nebude mít uživatel 'git' normální shellový přístup k vašemu serveru. Chcete-li nástroj použít, zadejte pro přihlašovací shell vašeho uživatele `git-shell` místo bash nebo csh. V takovém případě pravděpodobně budete muset upravit soubor `/etc/passwd`: $ sudo vim /etc/passwd @@ -273,7 +278,7 @@ Uživatel 'git' nyní může používat SSH připojení k odesílání a stahov ## Veřejný přístup ## -A co když chcete u svého projektu nastavit anonymní oprávnění pro čtení? Nehostujete třeba interní soukromý projekt, ale „open source“ projekt. Nebo možná máte několik serverů průběžné integrace, které se neustále mění a vy nechcete stále generovat SSH klíče, rádi byste vždy přidali jen obyčejné anonymní oprávnění pro čtení. +A co když chcete u svého projektu nastavit anonymní oprávnění pro čtení? Nehostujete třeba interní soukromý projekt, ale „open source“ projekt. Nebo možná máte několik serverů průběžné integrace, které se neustále mění a vy nechcete stále generovat SSH klíče. Rádi byste vždy přidali jen obyčejné anonymní oprávnění pro čtení. Patrně nejjednodušším způsobem pro menší týmy je spustit statický webový server s kořenovým adresářem dokumentů, v němž budou uloženy vaše Git repozitáře, a zapnout zásuvný modul `post-update`, o kterém jsme se zmínili už v první části této kapitoly. Můžeme pokračovat v našem předchozím příkladu. Řekněme, že máte repozitáře uloženy v adresáři `/opt/git` a na vašem počítači je spuštěn server Apache. Opět, můžete použít jakýkoli webový server. Pro názornost ale ukážeme některá základní nastavení serveru Apache, abyste získali představu, co vás může čekat. @@ -283,12 +288,17 @@ Nejprve ze všeho budete muset zapnout zásuvný modul: $ mv hooks/post-update.sample hooks/post-update $ chmod a+x hooks/post-update -Jestliže používáte verzi systému Git starší než 1.6, nebude příkaz `mv` nutný. Git začal pojmenovávat příklady zásuvných modulů příponou „.sample“ teprve nedávno. - Jaká je funkce zásuvného modulu `post-update`? V principu vypadá asi takto: $ cat .git/hooks/post-update #!/bin/sh + # + # An example hook script to prepare a packed repository for use over + # dumb transports. + # + # To enable this hook, rename this file to "post-update". + # + exec git-update-server-info Znamená to, že až budete odesílat data na server prostřednictvím SSH, Git spustí tento příkaz a aktualizuje soubory vyžadované pro přístup přes HTTP. @@ -316,7 +326,7 @@ Tímto způsobem můžete během pár minut nastavit oprávnění pro čtení za ## GitWeb ## -Nyní, když máte ke svému projektu nastavena základní oprávnění pro čtení/zápis a pouze pro čtení, možná budete chtít nastavit jednoduchou online vizualizaci. Git vám nabízí CGI skript s názvem GitWeb, který slouží k tomuto účelu. Jak GitWeb funguje, na to se můžete podívat např. na stránkách `http://git.kernel.org` (viz obrázek 4-1). +Nyní, když máte ke svému projektu nastavena základní oprávnění pro čtení/zápis a pouze pro čtení, možná budete chtít nastavit jednoduchou online vizualizaci. Git vám nabízí CGI skript s názvem GitWeb, který se k tomuto účelu běžně používá. V činnosti můžete GitWeb pozorovat například na stránkách `http://git.kernel.org` (viz obrázek 4-1). Insert 18333fig0401.png Obrázek 4-1. Online uživatelské rozhraní GitWeb @@ -354,7 +364,7 @@ Všimněte si, že musíte příkazu pomocí proměnné `GITWEB_PROJECTROOT` sd -Také GitWeb může být obsluhován jakýmkoli webovým serverem umožňujícím CGI. Chcete-li používat jakýkoli jiný server, nemělo by být nastavení obtížné. V tomto okamžiku byste měli být schopni prohlížet své repozitáře online na adrese `http://gitserver/` a používat `http://git.gitserver` ke klonování a vyzvedávání repozitářů prostřednictvím protokolu HTTP. +Znovu připomeňme, že GitWeb může být obsluhován jakýmkoli webovým serverem podporujícím CGI. Chcete-li používat jakýkoli jiný server, nemělo by být nastavení obtížné. V tomto okamžiku byste měli být schopni prohlížet své repozitáře online na adrese `http://gitserver/` a používat `http://git.gitserver` ke klonování a vyzvedávání repozitářů prostřednictvím protokolu HTTP. ## Gitosis ## @@ -364,13 +374,13 @@ Proto možná rádi přejdete na rozšířený softwarový projekt „Gitosis“ Instalace nástroje Gitosis sice nepatří mezi nejsnazší, ale není ani příliš složitá. Nejjednodušší je k ní použít linuxový server – tyto příklady používají běžný Ubuntu server 8.10. -Gitosis vyžaduje některé nástroje v jazyce Python, a proto první, co musíte udělat, je nainstalovat balíček nástrojů nastavení Python, který je v Ubuntu dostupný jako python-setuptools: +Gitosis vyžaduje některé nástroje v jazyce Python, a proto první, co musíte udělat, je nainstalovat pythonovský balíček setuptools, který je v Ubuntu dostupný jako python-setuptools: $ apt-get install python-setuptools Dále naklonujte a nainstalujte Gitosis z hlavní stránky projektu: - $ git clone git://eagain.net/gitosis.git + $ git clone https://github.com/tv42/gitosis.git $ cd gitosis $ sudo python setup.py install @@ -382,7 +392,7 @@ Gitosis teď bude spravovat klíče za vás. Proto je třeba, abyste odstranili $ mv /home/git/.ssh/authorized_keys /home/git/.ssh/ak.bak -Dále musíte znovu zapnout shell na uživatele 'git', jestliže jste ho změnili na příkaz `git-shell`. Uživatelé se stále ještě nebudou moci přihlásit, ale Gitosis za vás bude provádět správu. V souboru `/etc/passwd` tak nyní změníme řádek: +Dále musíte znovu zapnout shell na uživatele 'git', jestliže jste ho změnili na příkaz `git-shell`. Uživatelé se stále ještě nebudou moci přihlásit, ale Gitosis za vás bude provádět správu. Takže v souboru `/etc/passwd` změňte následující řádek git:x:1000:1000::/home/git:/usr/bin/git-shell @@ -390,21 +400,21 @@ zpět na git:x:1000:1000::/home/git:/bin/sh -V tomto okamžiku můžeme inicializovat nástroj Gitosis. Učiníte tak spuštěním příkazu `gitosis-init` se svým osobním veřejným klíčem. Není-li váš veřejný klíč na serveru, bude ho tam nutné zkopírovat: +V tomto okamžiku můžeme inicializovat nástroj Gitosis. Učiníte tak spuštěním příkazu `gitosis-init` se svým osobním veřejným klíčem. Není-li váš veřejný klíč na serveru, musíte ho tam nakopírovat: $ sudo -H -u git gitosis-init < /tmp/id_dsa.pub Initialized empty Git repository in /opt/git/gitosis-admin.git/ Reinitialized existing Git repository in /opt/git/gitosis-admin.git/ -Uživatel s tímto klíčem poté bude moci měnit hlavní repozitář Git, který kontroluje nastavení nástroje Gitosis. Dále je třeba ručně nastavit právo spuštění na skriptu `post-update` pro nový řídicí repozitář. +Uživatel s tímto klíčem poté bude moci měnit hlavní repozitář Git, kterým se ovládá nastavení nástroje Gitosis. Dále je třeba ručně nastavit právo spuštění na skriptu `post-update` pro nový řídicí repozitář. $ sudo chmod 755 /opt/git/gitosis-admin.git/hooks/post-update -Nyní máte vše hotovo. Pokud jste nastavení provedli správně, můžete vyzkoušet SSH přístup na server jako uživatel, pro kterého jste přidali veřejný klíč při inicializaci nástroje Gitosis. Mělo by se zobrazit asi následující: +Teď to můžete rozjet. Pokud jste nastavení provedli správně, můžete vyzkoušet SSH přístup na server jako uživatel, pro kterého jste přidali veřejný klíč při inicializaci nástroje Gitosis. Mělo by se zobrazit asi následující: $ ssh git@gitserver PTY allocation request failed on channel 0 - fatal: unrecognized command 'gitosis-serve schacon@quaternion' + ERROR:gitosis.serve.main:Need SSH_ORIGINAL_COMMAND in environment. Connection to gitserver closed. To znamená, že vás Gitosis sice rozpoznal, ale nedovolí vám přístup, protože se nepokoušíte zadat žádný příkaz Git. Provedeme tedy skutečný příkaz systému Git a naklonujeme řídicí repozitář Gitosis: @@ -428,28 +438,28 @@ Pokud se podíváte na soubor `gitosis.conf`, měl by udávat pouze informace o [gitosis] [group gitosis-admin] - writable = gitosis-admin members = scott + writable = gitosis-admin Tato informace znamená, že uživatel 'scott' – ten, jehož veřejným klíčem jste inicializovali Gitosis – je jediným uživatelem, který má přístup k projektu `gitosis-admin`. Nyní přidáme nový projekt. Přidáte novou část s názvem `mobile`, která bude obsahovat seznam vývojářů vašeho mobilního týmu a projektů, k nimž tito vývojáři potřebují přístup. Protože je v tuto chvíli jediným uživatelem v systému 'scott', přidáte ho jako jediného člena a vytvoříte pro něj nový projekt s názvem `iphone_project`: [group mobile] - writable = iphone_project members = scott + writable = iphone_project Pokaždé, když provedete změny v projektu `gitosis-admin`, musíte tyto změny zapsat a odeslat je zpět na server, aby nabyly účinnosti: $ git commit -am 'add iphone_project and mobile group' - [master]: created 8962da8: "changed name" - 1 files changed, 4 insertions(+), 0 deletions(-) - $ git push + [master 8962da8] add iphone_project and mobile group + 1 file changed, 4 insertions(+) + $ git push origin master Counting objects: 5, done. - Compressing objects: 100% (2/2), done. - Writing objects: 100% (3/3), 272 bytes, done. - Total 3 (delta 1), reused 0 (delta 0) - To git@gitserver:/opt/git/gitosis-admin.git + Compressing objects: 100% (3/3), done. + Writing objects: 100% (3/3), 272 bytes | 0 bytes/s, done. + Total 3 (delta 0), reused 0 (delta 0) + To git@gitserver:gitosis-admin.git fb27aec..8962da8 master -> master Do nového projektu `iphone_project` teď můžete odeslat svá první data: přidejte do lokální verze projektu svůj server jako vzdálený repozitář a odešlete změny. Od této chvíle už nebudete muset ručně vytvářet holé repozitáře pro nové projekty na serveru. Gitosis je vytvoří automaticky, jakmile zjistí první odeslání dat: @@ -458,7 +468,7 @@ Do nového projektu `iphone_project` teď můžete odeslat svá první data: př $ git push origin master Initialized empty Git repository in /opt/git/iphone_project.git/ Counting objects: 3, done. - Writing objects: 100% (3/3), 230 bytes, done. + Writing objects: 100% (3/3), 230 bytes | 0 bytes/s, done. Total 3 (delta 0), reused 0 (delta 0) To git@gitserver:iphone_project.git * [new branch] master -> master @@ -474,20 +484,20 @@ Na tomto projektu chcete spolupracovat s přáteli, a proto budete muset znovu p Nyní je můžete všechny přidat do týmu 'mobile', čímž získají oprávnění pro čtení i pro zápis k `iphone_project`: [group mobile] - writable = iphone_project members = scott john josie jessica + writable = iphone_project Až tuto změnu zapíšete a odešlete, všichni čtyři uživatelé budou moci z tohoto projektu číst a zapisovat do něj. Gitosis nabízí také jednoduchou správu přístupu. Pokud chcete, aby měl John u projektu pouze oprávnění pro čtení, můžete provést následující: [group mobile] - writable = iphone_project members = scott josie jessica + writable = iphone_project [group mobile_ro] - readonly = iphone_project members = john + readonly = iphone_project John nyní může naklonovat projekt a stahovat jeho aktualizace, ale Gitosis mu neumožní, aby odesílal data zpět do projektu. Takových skupin můžete vytvořit libovolně mnoho. Každá může obsahovat různé uživatele a projekty. Jako jednoho ze členů skupiny můžete zadat také celou jinou skupinu (použijete pro ni předponu `@`). Všichni její členové se tím automaticky zdědí. @@ -495,37 +505,37 @@ John nyní může naklonovat projekt a stahovat jeho aktualizace, ale Gitosis mu members = scott josie jessica [group mobile] - writable = iphone_project members = @mobile_committers + writable = iphone_project [group mobile_2] - writable = another_iphone_project members = @mobile_committers john + writable = another_iphone_project Máte-li jakékoli problémy, může vám pomoci zadání `loglevel=DEBUG` do části `[gitosis]`. Pokud jste odesláním nesprávné konfigurace ztratili oprávnění k odesílání dat, můžete ručně opravit soubor na serveru v adresáři `/home/git/.gitosis.conf` – jedná se o soubor, z nějž Gitosis načítá data. Po odeslání dat do projektu bude soubor `gitosis.conf`, který jste právě odeslali, umístěn do tohoto adresáře. Pokud soubor ručně upravíte, zůstane v této podobě až do dalšího úspěšného odeslání do projektu `gitosis-admin`. ## Gitolite ## -Git se stal hodně populárním v korporátním prostředí, které obvykle mívá další doplňující požadavky na kontrolu přístupu. Nástroj Gitolite byl vytvořen právě na řešení těchto požadavků. +Tato podkapitola slouží k rychlému seznámení s Gitolite a uvádí základní pokyny pro instalaci a nastavení. Nemůže ale nahradit ohromný objem [dokumentace][gltoc], která se s Gitolite dodává. Tato podkapitola se může občas změnit, takže se možná chcete podívat na její [poslední verzi][gldpg]. [gldpg]: http://sitaramc.github.com/gitolite/progit.html [gltoc]: http://sitaramc.github.com/gitolite/master-toc.html Gitolite je autorizační vrstva nad gitem, která při autentizaci spoléhá na `sshd` nebo `httpd`. (Připomeňme si: autentizace spočívá v rozpoznání uživatele, autorizací rozumíme rozhodování, zda má povolení k provádění toho, co se provést pokouší.) -Gitolite umožňuje nastavit přístupová práva nejen na repozitáře (podobně jako Gitosis), ale také na větve a značky v každém repozitáři. To znamená, že lze nastavit, aby určití lidé mohli odesílat jen do určité reference (větve nebo značky) a do jiné ne. +Gitolite umožňuje nastavit přístupová práva nejen na repozitáře (podobně jako Gitosis), ale také na větve a značky v každém repozitáři. To znamená, že lze nastavit, aby určití lidé mohli odesílat jen do určité větve (nebo určité značky; obecně „refs“), ale do jiné ne. ### Instalace ### -Instalace Gitolite je velmi jednoduchá a to i když nebudete číst obsáhlou dokumentaci, která je k dispozici. Budete potřebovat účet na nějakém unixovém serveru (bylo testováno na různých distribucích Linuxu a na Solarisu 10), kde musí být nainstalovány git, Perl a SSH server kompatibilní s OpenSSH. V příkladech uvedených níže budeme používat účet `git` na serveru `gitserver`. +Instalace Gitolite je velmi jednoduchá a to i když si nepřečtete obsáhlou dokumentaci, která je k dispozici. Budete potřebovat účet na nějakém unixovém serveru. Pokud už jsou nainstalovány nástroje Git, Perl a SSH server kompatibilní s OpenSSH, nebudete potřebovat ani přístup root. V příkladech uvedených níže budeme používat účet `git` na serveru `gitserver`. -Nástroj Gitolite je ve smyslu „serverového“ softwaru poněkud neobvyklý. Přístup se realizuje přes ssh, takže každá serverová userid je potenciálně „hostitelem gitolite“ (gitolite host). Teď si popíšeme nejjednodušší způsob instalace. V dokumentaci naleznete další metody. +Nástroj Gitolite je ve smyslu „serverového“ softwaru poněkud neobvyklý. Přístup se realizuje přes SSH, takže každá serverová userid je potenciálně „hostitelem gitolite“ (gitolite host). Teď si popíšeme nejjednodušší způsob instalace. V dokumentaci naleznete další metody. -Začněte tím, že na serveru vytvoříte uživatele nazvaného `git` a přihlásíte se na něj. Z vaší pracovní stanice nakopírujte svůj veřejný ssh klíč (pokud jste spustili `ssh-keygen` s implicitními hodnotami, jde o soubor `~/.ssh/id_rsa.pub`) a přejmenujte jej na `VaseJmeno.pub`. Potom proveďte následující příkazy: +Začněte tím, že na serveru vytvoříte uživatele nazvaného `git` a přihlásíte se na něj. Z vaší pracovní stanice nakopírujte svůj veřejný SSH klíč (pokud jste spustili `ssh-keygen` s implicitními hodnotami, jde o soubor `~/.ssh/id_rsa.pub`) a přejmenujte jej na `.pub` (v příkladech budeme používat `scott.pub`). Potom proveďte následující příkazy: $ git clone git://github.com/sitaramc/gitolite $ gitolite/install -ln - # předpokládá existenci $HOME/bin a uvedení tohoto adresáře v $PATH + # assumes $HOME/bin exists and is in your $PATH $ gitolite setup -pk $HOME/scott.pub Poslední příkaz vytvoří na serveru nový gitovský repozitář nazvaný `gitolite-admin`. @@ -538,7 +548,7 @@ Základní rychlá metoda instalace bude většině lidí vyhovovoat. V případ ### Konfigurační soubor a pravidla přístupu ### -Přepněte se do repozitáře `gitolite-admin` (je umístěn ve vašem domácím adresáři), jakmile je instalace dokončena, a podívejte se co tam je: +Jakmile je instalace dokončena, přepněte se do repozitáře `gitolite-admin`, který jste naklonovali na váš počítač, a podívejte se co tam je: $ cd ~/gitolite-admin/ $ ls @@ -558,9 +568,9 @@ Všimněte si, že „scott“ (jméno veřejného klíče v dříve použitém Přidávání dalších uživatelů je snadné. Pokud chceme přidat uživatele „alice“, získáme její veřejný klíč, pojmenujeme jej `alice.pub` a umístíme jej do adresáře `keydir`. Je součástí klonu repozitáře `gitolite-admin`, který jsme právě vytvořili na pracovní stanici. Přidáme, potvrdíme a odešleme změny (add, commit, push). Tím jsme dosáhli přidání uživatele. -Syntaxe konfiguračního souboru pro Gitolite je dobře dokumentovaná, takže zde uvedu jen pár zajímavých věcí. +Syntaxe konfiguračního souboru pro Gitolite je dobře dokumentovaná, takže zde zdůrazníme jen pár věcí. -Pro usnadnění můžete dávat uživatele i repozitáře do skupin. Jména skupin jsou podobná jako makra; když je definujete, je úplně jedno jestli jde o projekty nebo uživatele; rozdíl to je až v momentu, kdy „makro“ použijete. +Pro usnadnění můžete uživatele i repozitáře sdružovat do skupin. Jména skupin se chovají jako makra; když je definujete, je úplně jedno jestli jde o projekty nebo uživatele; rozdíl se pozná až v momentu, kdy „makro“ *použijete*. @oss_repos = linux perl rakudo git gitolite @secret_repos = fenestra pear @@ -578,7 +588,7 @@ Můžete nastavovat přístupová práva na úrovni referencí. Skupina interns RW refs/tags/rc[0-9] = @engineers RW+ = @admins -Výraz za `RW` nebo `RW+` je regulární výraz (regex), se kterým se porovnává jméno odesílané reference. Nazvěme jej tedy „refex“! Refex může mít samozřejmě mnohem více použití než je tady ukázáno, takže si dejte pozor ať to nepřeženete, zvláště pokud se necítíte experty na regulární výrazy. +Výraz za `RW` nebo `RW+` je regulární výraz (regex), se kterým se porovnává jméno odesílané reference (ref). Nazvěme jej tedy „refex“! Refex může mít samozřejmě mnohem více použití než je tady ukázáno, takže si dejte pozor ať to nepřeženete, zvláště pokud nejste kovaní v perlovských regulárních výrazech. Gitolite přidává prefix `refs/heads/` jako usnadnění syntaxe, pokud refex nezačíná na `refs/`, jak jste mohli odhadnout z příkladu. @@ -587,50 +597,50 @@ Důležitou vlastností syntaxe konfiguračního souboru je to, že všechna pra repo gitolite RW+ = sitaram -Toto pravidlo se pak přidá do skupiny pravidel `gitolite` repozitáře. +Toto pravidlo se pak přidá do skupiny pravidel repozitáře `gitolite`. Teď by vás mohlo zajímat, jak jsou vlastně pravidla pro přístup aplikována, pojďme se na to tedy krátce podívat. -V gitolite jsou dvě úrovně kontroly přístupů. První je úroveň repozitářů; jestliže máte práva na čtení (nebo zápis) k jakékoliv referenci v repozitáři, máte tím práva na čtení (nebo zápis) k tomuto repozitáři. Tohle je jediná možnost jakou měl nástroj Gitosis. +V Gitolite jsou dvě úrovně kontroly přístupů. První je úroveň repozitářů; jestliže máte práva na čtení (nebo zápis) *k jakékoliv* referenci v repozitáři, máte tím práva na čtení (nebo zápis) k tomuto repozitáři. Tohle je jediná možnost jakou měl nástroj Gitosis. -Druhá úroveň je pouze pro práva pro „zápis“ a je podle větve nebo značky v repozitáři. Uživatelské jméno uživatele snažícího se o přístup (`W` nebo `+`) a jméno reference, kterou uživatel chce aktualizovat, jsou dané. Pravidla pro přístup jsou procházena postupně v pořadí, tak jak jsou uvedena v konfiguračním souboru a hledají se záznamy odpovídající této kombinaci uživatelského jména a reference (nezapomeňte ale, že refname se porovnává jako regulární výraz nikoliv jako pouhý řetězec). Jestliže je nalezen odpovídající záznam, odesílání je povoleno. Pokud není nalezeno nic, je přístup zamítnut. +Druhá úroveň se dá použít jen pro práva pro „zápis“ a vázána na větve nebo značky v repozitáři. Uživatelské jméno uživatele snažícího se o přístup (`W` nebo `+`) a jméno reference, kterou uživatel chce aktualizovat, jsou dané. Pravidla pro přístup jsou procházena postupně v pořadí, tak jak jsou uvedena v konfiguračním souboru a hledají se záznamy odpovídající této kombinaci uživatelského jména a reference (nezapomeňte ale, že refname se porovnává jako regulární výraz nikoliv jako pouhý řetězec). Jestliže je nalezen odpovídající záznam, odesílání je povoleno. Pokud není nalezeno nic, je přístup zamítnut. -### Rozšířená kontrola přístupu ve větvi „rebel“ ### +### Rozšířené řízení přístupu pravidly typu „odmítnutí“ ### -Jak můžete vidět výše, práva musí být jedno z nastavení `R`, `RW` nebo `RW+`. Dříve zmíněná větev „rebel“ přidává ještě jedno další právo: `-`, znamenající „odmítnutí“. To dává mnohem více možností za cenu zvýšení složitosti, protože nyní už není nenalezení odpovídajícího záznamu při procházení pravidel jedinou možností, jak může být přístup zamítnut. Takže nyní už na pořadí pravidel záleží! +Prozatím jsme si ukázali jen oprávnění nastavená na jednu z hodnot `R`, `RW` nebo `RW+`. Ale Gitolite dovoluje nastavení dalšího oprávnění: `-` s významem „odmítnutí“. To vám dává mnohem více možností, ale za cenu zvýšení složitosti. Popadnutí sítem pravidel už totiž není *jedinou* možností vedoucí k zamítnutí přístupu. *Záleží na pořadí pravidel!* -Řekněme, že ve výše uvedené situaci budeme chtít, aby skupina engineers mohla vracet změny v jakékoliv větvi s výjimkou větvě „hlavní“ a větve „integ“. To se nedá nastavit pomocí normální syntaxe, ale s pomocí větve „rebel“ podle následujícího postupu: +Řekněme, že ve výše uvedené situaci budeme chtít, aby skupina engineers mohla vracet změny v jakékoliv větvi *s výjimkou* větví `master` a `integ`. Udělá se to následovně: RW master integ = @engineers - master integ = @engineers RW+ = @engineers -Pravidla se znovu budou procházet postupně až do momentu, kdy bude nalezeno odpovídají pravidlo nebo bude přístup zamítnut. Odeslání do hlavní větve nebo větve „integ“, která nevracejí zpět změny, jsou povolena prvním pravidlem. Odeslání, která vracejí změny do těchto větví, neodpovídají prvnímu pravidlu. Porovnají se tedy s druhým pravidlem a na jeho základě budou zamítnuty. Odeslání (bez ohledu na to zda se jedná o vracení změn nebo ne) do jiných referencí než hlavní a „integ“ nebudou odpovídat ani prvnímu ani druhému pravidlu a budou tedy díky třetímu pravidlu povolena. +Pravidla se budou opět procházet shora dolů až do momentu, kdy narazíte na shodu s vaším režimem přístupu nebo na pravidlo typu odmítnutí (deny). Odeslání do větve `master` nebo `integ`, která nevracejí zpět změny (non-rewind push), jsou povolena prvním pravidlem. Odeslání, která vracejí změny (rewind push) do těchto větví, neodpovídají prvnímu pravidlu. Porovnají se tedy s druhým pravidlem a na jeho základě budou zamítnuty. Jakékoliv odeslání (bez ohledu na to zda se jedná o vracení změn nebo ne) do jiných referencí než `master` nebo `integ` nebudou odpovídat ani prvnímu ani druhému pravidlu, a proto bude díky třetímu pravidlu povoleno. ### Omezení odesílání změn vázané na soubory ### -K omezení odesílání do určitých větví a určitými uživateli můžete přidat také omezení určující, které soubory mohou uživatelé měnit. Například soubor Makefile (a možná některé programy) by asi neměl kdokoliv měnit, protože je na něm závislá řada dalších věcí. Pokud se neupraví *správným způsobem*, něco by se pokazilo. Nástroji gitolite můžeme říct: +K omezení odesílání do určitých větví a určitými uživateli můžete přidat také omezení určující, které soubory mohou uživatelé měnit. Například soubor Makefile (a možná některé programy) by asi neměl kdokoliv měnit, protože je na něm závislá řada dalších věcí. Pokud se neupraví *správným způsobem*, něco by se pokazilo. Nástroji Gitolite můžeme říct: repo foo RW = @junior_devs @senior_devs - VREF/NAME/Makefile = @junior_devs -Uživatelé, kteří přecházejí ze starší verze gitolite by si měli dát pozor na to, že v souvislosti s uvedeným rysem došlo k výrazné změně chování. Věnujte prosím pozornost detailům, které jsou uvedeny v příručce pro přechod k nové verzi. +Uživatelé, kteří přecházejí ze starší verze Gitolite by si měli dát pozor na to, že v souvislosti s uvedeným rysem došlo k výrazné změně chování. Věnujte prosím pozornost detailům, které jsou uvedeny v příručce pro přechod k nové verzi. ### Osobní větve ### Konečně Gitolite má také funkci, která se nazývá „osobní větve“ (nebo raději „jmenný prostor osobních větví“) a může být velmi užitečná v korporátním prostředí. -Hodně výměny kódu probíhá v otevřeném git světě metodou „prosím stáhněte si“. V korporátním prostředí ovšem nebývá jakýkoliv neautorizovaný přístup vítán a pracovní stanice vývojáře nemůže provádět autentizaci, takže můžete na centrální server odesílat, ale musíte požádat někoho jiného, když odtud chcete stahovat. +Hodně výměny kódu probíhá v otevřeném gitovém světě metodou „prosím stáhněte si“. V korporátním prostředí ovšem nebývá jakýkoliv přístup bez prokázání totožnosti vítán a pracovní stanice vývojáře nemůže provádět autentizaci, takže můžete na centrální server odesílat, ale musíte požádat někoho jiného, když odtud chcete stahovat. -To by za normálních okolností způsobilo stejný zmatek ve jménech větví jako v centralizovaných systémech správy verzí a navíc nastavování přístupových práv by se stalo noční můrou pro administrátory. +To by za normálních okolností způsobilo stejný zmatek ve jménech větví jako v centralizovaných systémech správy verzí a navíc nastavování přístupových práv by administrátorovi přidalo práci. Gitolite vám umožní nadefinovat pro každého vývojáře jmenné prostory s prefixy „personal“ nebo „scratch“ (např. `refs/personal//*`). Podrobnosti hledejte v dokumentaci. ### „Wildcard“ repozitáře ### -Gitolite vám umožní určit repozitáře zástupnými znaky (wildcards; ve skutečnosti jde o perlovské regulární výrazy) -- například k náhodnému výběru zadání příkladu můžeme použít `assignments/s[0-9][0-9]/a[0-9][0-9]`. Umožní nám též přidělit nový režim oprávnění (`C`), který uživatelům povoluje vytvářet repozitáře popsané zástupnými znaky, automaticky přidělí vlastnictví konkrétnímu uživateli, který jej vytvořil, umožní mu přidělit oprávnění `R` a `RW` dalším spolupracovníkům atd. Podrobnosti opět hledejte v dokumentaci. +Gitolite vám umožní určit repozitáře zástupnými znaky (wildcards; ve skutečnosti jde o perlovské regulární výrazy) -- jako například u náhodně vybraného příkladu `assignments/s[0-9][0-9]/a[0-9][0-9]`. Umožní nám též přidělit nový režim oprávnění (`C`), který uživatelům povoluje vytvářet repozitáře popsané zástupnými znaky, automaticky přidělí vlastnictví konkrétnímu uživateli, který jej vytvořil, umožní mu přidělit oprávnění `R` a `RW` dalším spolupracovníkům atd. Podrobnosti opět hledejte v dokumentaci. ### Další vlastnosti ### @@ -638,7 +648,7 @@ Vysvětlení Gitolite završíme přehledem několika vlastností, které jsou d **Logování:** Gitolite loguje všechny úspěšné přístupy. Jestliže máte volná pravidla pro přidělování oprávnění vracet změny (práva `RW+`) a stane se, že někdo takto „zkazí“ větev `master`, je tu ještě log soubor, který vám zachrání život, protože v něm můžete postižené SHA najít. -**Přehledy uživatelských oprávnění:** Další příjemnou vlastností je to, co se stane, pokud se pouze pokusíte připojit pomocí SSH na server. Gitolite vám ukáže, ke kterým repozitářům máte přístup a s jakoými oprávněními. Příklad: +**Přehledy uživatelských oprávnění:** Další příjemnou vlastností je to, co se stane, pokud se pouze pokusíte připojit pomocí SSH na server. Gitolite vám ukáže, ke kterým repozitářům máte přístup a s jakými oprávněními. Příklad: hello scott, this is git@git running gitolite3 v3.01-18-g9609868 on git 1.7.4.4 @@ -650,15 +660,15 @@ Vysvětlení Gitolite završíme přehledem několika vlastností, které jsou d R indic_web_input R shreelipi_converter -**Delegace:** Pro opravdu velké instalace můžete delegovat zodpovědnost za skupiny a repozitáře dalším lidem a nechat je samotné spravovat jednotlivé části. To snižuje vytížení hlavního administrátora, který tím přestává být úským místem správy. +**Delegace:** Pro opravdu velké instalace můžete delegovat zodpovědnost za skupiny a repozitáře dalším lidem a nechat je spravovat jednotlivé části nezávisle. To snižuje vytížení hlavního administrátora, který tím přestává být úzkým místem správy. **Zrcadlení:** Gitolite vám pomůže se správou více zrcadel a při výpadku hlavního serveru můžete snadno přepnout na jiný. ## Démon Git ## -Jestliže potřebujete ke svým projektům veřejný, neověřovaný přístup pro čtení, budete muset překročit hranice vymezené protokolem HTTP a začít používat protokol Git. Mluví pro něj především rychlost. Protokol Git je daleko výkonnější, a proto také rychlejší než protokol HTTP a svým uživatelů tím ušetří spoustu času. +Jestliže potřebujete ke svým projektům přístup pro čtení bez ověřování totožnosti, budete muset obejít protokol HTTP a začít používat protokol Git. Mluví pro něj především rychlost. Protokol Git je daleko výkonnější, a proto také rychlejší než protokol HTTP, takže uživatelům ušetří nějaký čas. -I v tomto případě se jedná o neověřený přístup pouze pro čtení. Pokud protokol používáte na serveru mimo firewall, mělo by to být pouze u projektů, které jsou veřejně viditelné okolnímu světu. Pokud je server, na kterém protokol spouštíte, uvnitř firewallu, můžete ho používat u projektů, k nimž má přístup pro čtení velký počet lidí nebo počítačů (servery průběžné integrace nebo servery sestavení), jimž nechcete jednotlivě přiřazovat SSH klíče. +I v tomto případě se jedná o přístup pouze pro čtení bez ověřování totožnosti. Pokud protokol používáte na serveru mimo firewall, mělo by to být pouze u projektů, které jsou veřejně viditelné okolnímu světu. Pokud je server, na kterém protokol spouštíte, uvnitř firewallu, můžete ho používat u projektů, k nimž má přístup pro čtení velký počet lidí nebo počítačů (servery průběžné integrace nebo servery sestavení), jimž nechcete jednotlivě přiřazovat SSH klíče. Ať tak či tak, na protokolu Git jistě oceníte jeho snadné nastavení. V podstatě je třeba spustit tento příkaz: @@ -689,7 +699,7 @@ Při restartování počítače se démon Git spustí automaticky. V případě V jiných systémech možná budete chtít použít `xinetd`, skript systému `sysvinit`, nebo podobný skript – můžete-li spouštět příkaz démonizovaný a sledovaný. -Dále budete muset svému serveru Gitosis sdělit, k jakým repozitářům si přejete povolit neověřený serverový přístup Git. Pokud přidáte jednu část pro každý repozitář, můžete určit repozitáře, z nichž si přejete dovolit démonovi Git načítat data. Chcete-li povolit přístup přes protokol Git k projektu `iphone_project`, přidejte ho na konec souboru `gitosis.conf`: +Dále budete muset svému serveru Gitosis sdělit, k jakým repozitářům si přejete povolit neautentizovaný serverový přístup Git. Pokud pro každý repozitář přidáte sekci, můžete určit repozitáře, z nichž si přejete dovolit démonovi Git načítat data. Chcete-li povolit přístup přes protokol Git k projektu `iphone_project`, přidejte ho na konec souboru `gitosis.conf`: [repo iphone_project] daemon = yes @@ -701,7 +711,7 @@ Pokud nechcete používat Gitosis, ale chcete nastavit démona Git, budete muset $ cd /path/to/project.git $ touch git-daemon-export-ok -Přítomnost tohoto souboru systému Git sděluje, že si přejete obsluhovat tento projekt bez ověřování. +Přítomnost tohoto souboru systému Git sděluje, že si přejete obsluhovat tento projekt bez ověřování totožnosti. Gitosis může také určovat, jaké projekty bude zobrazovat GitWeb. Nejprve budete muset do souboru `/etc/gitweb.conf` vložit následující: @@ -720,15 +730,15 @@ Pokud teď zapíšete a odešlete projekt, GitWeb začne automaticky zobrazovat ## Hostování projektů Git ## -Pokud nemáte chuť absolvovat celý proces nastavování vlastního serveru Git, existuje několik možností hostování vašich projektů Git na externím specializovaném hostingovém místě. Toto řešení vám nabízí celou řadu výhod. Hostingové místo má většinou velmi rychlé nastavení, snadno se na něm spouštějí projekty a nevyžaduje od vás správu ani monitoring serveru. Dokonce i když budete nastavovat a spouštět interně svůj vlastní server, budete možná přesto chtít použít veřejné hostingové místo pro otevřený zdrojový kód – komunita open source vývojářů si vás tak snáze najde a pomůže vám. +Pokud nemáte chuť absolvovat celý proces nastavování vlastního serveru Git, existuje několik možností hostování vašich projektů Git na externím specializovaném hostingovém místě. Toto řešení vám nabízí celou řadu výhod. Hostingové místo má většinou velmi rychlé nastavení, snadno se na něm zakládají projekty a nevyžaduje od vás správu ani monitoring serveru. Dokonce i když budete nastavovat a spouštět interně svůj vlastní server, budete možná přesto chtít použít veřejné hostingové místo pro otevřený zdrojový kód – komunita open source vývojářů si vás tak snáze najde a pomůže vám. -V dnešní době můžete vybírat z velkého počtu možností hostingu. Každá má jiné klady a zápory. Aktuální seznam těchto míst najdete na stránce GitHosting, dostupné z hlavní stránky GitWiki: +V dnešní době můžete vybírat z velkého počtu možností hostingu. Každá má jiné klady a zápory. Aktuální seznam těchto míst najdete na následující stránce: https://git.wiki.kernel.org/index.php/GitHosting Protože se tu nemůžeme věnovat všem možnostem a protože shodou okolností na jednom hostingovém místě pracuji, využijeme tuto část k tomu, abychom ukázali nastavení účtu a vytvoření nového projektu na serveru GitHub. Získáte tak představu, co všechno vás čeká. -GitHub je zdaleka největším hostingovým místem pro projekty Git s otevřeným zdrojovým kódem a je zároveň jedním z velmi mála těch, která nabízejí možnosti jak veřejného, tak soukromého hostingu. Na jednom místě tak můžete mít uložen jak otevřený zdrojový kód, tak soukromý komerční kód. GitHub se ostatně soukromě podílel i na vzniku této knihy. +GitHub je zdaleka největším hostingovým místem pro projekty Git s otevřeným zdrojovým kódem a je zároveň jedním z velmi mála těch, která nabízejí možnosti jak veřejného, tak soukromého hostingu. Na jednom místě tak můžete mít uložen jak otevřený zdrojový kód, tak soukromý komerční kód. Možnost soukromého použití GitHub jsme ostatně používali pro spolupráci při vzniku této knihy. ### GitHub ### @@ -738,7 +748,7 @@ GitHub je zároveň komerční společnost, jejíž finanční příjmy plynou z ### Založení uživatelského účtu ### -První věcí, kterou budete muset udělat, je vytvoření bezplatného uživatelské účtu. Jestliže na stránce „Pricing and Signup“ (`http://github.com/plans`) kliknete u bezplatného účtu (Free) na tlačítko „Sign Up“ (viz obrázek 4-2), přejdete na registrační stránku. +První věcí, kterou budete muset udělat, je vytvoření bezplatného uživatelské účtu. Jestliže na stránce „Pricing and Signup“ (`https://github.com/pricing`) kliknete u bezplatného účtu (Free) na tlačítko „Sign Up“ (viz obrázek 4-2), přejdete na registrační stránku. Insert 18333fig0402.png Obrázek 4-2. Výběr typu účtu na serveru GitHub @@ -763,7 +773,7 @@ Začněte kliknutím na odkaz „create a new one“ (vytvořit nový) vedle nad Insert 18333fig0405.png Obrázek 4-5. Vytvoření nového repozitáře na serveru GitHub -Vše, co tu bezpodmínečně musíte udělat, je zadat název projektu. Kromě toho můžete přidat i jeho popis. Poté klikněte na tlačítko „Create Repository“ (Vytvořit repozitář). Nyní máte na serveru GitHub vytvořen nový repozitář (viz obrázek 4-6). +Vše, co tu opravdu musíte udělat, je zadat název projektu. Kromě toho můžete přidat i jeho popis. Poté klikněte na tlačítko „Create Repository“ (Vytvořit repozitář). Nyní máte na serveru GitHub vytvořen nový repozitář (viz obrázek 4-6). Insert 18333fig0406.png Obrázek 4-6. Záhlaví s informacemi o projektu na serveru GitHub @@ -795,7 +805,7 @@ Obrázek 4-8. Záhlaví projektu s veřejnou a soukromou adresou URL ### Import ze systému Subversion ### -Máte-li existující veřejný projekt Subversion, který byste rádi importovali do systému Git, GitHub vám s tím často ochotně pomůže. Dole na stránce s instrukcemi najdete odkaz na import ze systému Subversion. Pokud na něj kliknete, zobrazí se formulář s informacemi o importu a textové pole, kam můžete vložit adresu URL svého veřejného projektu Subversion (viz obrázek 4-9). +Máte-li existující veřejný projekt Subversion, který byste rádi importovali do systému Git, GitHub vám s tím obvykle pomůže. Dole na stránce s instrukcemi najdete odkaz na import ze systému Subversion. Pokud na něj kliknete, zobrazí se formulář s informacemi o importu a textové pole, kam můžete vložit adresu URL svého veřejného projektu Subversion (viz obrázek 4-9). Insert 18333fig0409.png Obrázek 4-9. Rozhraní importu ze systému Subversion @@ -830,20 +840,20 @@ Po odeslání projektu nebo jeho naimportování ze systému Subversion budete m Insert 18333fig0413.png Obrázek 4-13. Hlavní stránka projektu na serveru GitHub -Navštíví-li váš projekt ostatní uživatelé, tuto stránku uvidí. Obsahuje několik záložek k různým aspektům vašich projektů. Záložka „Commits“ zobrazuje seznam revizí v obráceném chronologickém pořadí, podobně jako výstup příkazu `git log`. Záložka „Network“ zobrazuje všechny uživatele, kteří rozštěpili váš projekt a přispěli do něj. Záložka „Downloads“ umožňuje nahrávat binární soubory k projektu a přidávat odkazy na tarbally a komprimované verze všech míst ve vašem projektu, které jsou označeny značkou (tagem). Záložka „Wiki“ vám nabízí stránku wiki, kam můžete napsat dokumentaci nebo jiné informace ke svému projektu. Záložka „Graphs“ graficky zobrazuje některé příspěvky a statistiky k vašemu projektu. Hlavní záložka „Source“, na níž se stránka otvírá, zobrazuje hlavní adresář vašeho projektu, a máte-li soubor README, automaticky ho zařadí na konec seznamu. Tato záložka obsahuje rovněž pole s informacemi o poslední zapsané revizi. +Navštíví-li váš projekt ostatní uživatelé, tuto stránku uvidí. Obsahuje několik záložek k různým aspektům vašich projektů. Záložka „Commits“ zobrazuje seznam revizí v obráceném chronologickém pořadí, podobně jako výstup příkazu `git log`. Záložka „Network“ zobrazuje všechny uživatele, kteří se odštěpili od vašeho projektu a zase do něj přispěli. Záložka „Downloads“ umožňuje nahrávat binární soubory k projektu a přidávat odkazy na tarbally a komprimované verze všech míst ve vašem projektu, které jsou označeny značkou (tagem). Záložka „Wiki“ vám nabízí stránku wiki, kam můžete napsat dokumentaci nebo jiné informace ke svému projektu. Záložka „Graphs“ graficky zobrazuje některé příspěvky a statistiky k vašemu projektu. Hlavní záložka „Source“, na níž se stránka otvírá, zobrazuje hlavní adresář vašeho projektu, a máte-li soubor README, automaticky pod adresářem projektu zobrazí jeho obsah. Tato záložka obsahuje rovněž pole s informacemi o poslední zapsané revizi. ### Štěpení projektů ### -Chcete-li přispět do existujícího projektu, k němuž nemáte oprávnění pro odesílání, umožňuje GitHub rozštěpení projektu. Pokud se dostanete na zajímavou stránku projektu a chtěli byste se do projektu zapojit, můžete kliknout na tlačítko „fork“ (rozštěpit) v záhlaví projektu a GitHub vytvoří kopii projektu pro vašeho uživatele. Do ní pak můžete odesílat revize. +Chcete-li přispět do existujícího projektu, k němuž nemáte oprávnění pro odesílání, umožňuje GitHub rozštěpení projektu. Pokud se dostanete na zajímavou stránku projektu a chtěli byste se do projektu zapojit, můžete kliknout na tlačítko „fork“ (rozštěpit -- doslova vidlička) v záhlaví projektu a GitHub vytvoří kopii projektu pro vašeho uživatele. Do ní pak můžete odesílat revize. -Díky tomu se projekty nemusí starat o přidávání uživatelů do role spolupracovníků, aby mohli odesílat své příspěvky. Uživatelé mohou projekt rozštěpit a odesílat do něj revize. Hlavní správce projektu tyto změny natáhne tím, že je přidá jako vzdálené repozitáře a začlení jejich data. +Díky tomu se projekty nemusí starat o přidávání uživatelů do role spolupracovníků, kteří by měli právo zápisu. Uživatelé mohou projekt rozštěpit a odesílat do něj revize. Hlavní správce projektu tyto změny natáhne tím, že je přidá jako vzdálené repozitáře a začlení jejich data. Chcete-li projekt rozštěpit, přejděte na stránku projektu (v tomto případě mojombo/chronic) a klikněte na tlačítko „fork“ v záhlaví (viz obrázek 4-14). Insert 18333fig0414.png Obrázek 4-14. Zapisovatelnou kopii jakéhokoli repozitáře získáte kliknutím na tlačítko „fork“. -Po několika sekundách přejdete na novou stránku svého projektu, která oznamuje, že je tento projekt rozštěpením (fork) jiného projektu (viz obrázek 4-15). +Po několika sekundách přejdete na novou stránku svého projektu, která oznamuje, že je tento projekt odštěpen (fork) z jiného projektu (viz obrázek 4-15). Insert 18333fig0415.png Obrázek 4-15. Vaše rozštěpení projektu @@ -858,4 +868,4 @@ Existuje několik možností, jak vytvořit a zprovoznit vzdálený repozitář Provoz vlastního serveru vám dává celou řadu možností kontroly a umožňuje provozovat server za vaším firewallem. Nastavení a správa takového serveru však obvykle bývají časově náročné. Umístíte-li data na hostovaný server, je jejich nastavení a správa jednoduchá. Svůj zdrojový kód však v takovém případě ukládáte na cizím serveru, což některé organizace nedovolují. -Mělo by být jasně dáno, které řešení nebo jaká kombinace řešení je vhodná pro vás a pro vaši organizaci. +Teď už byste se měli umět rozhodnout, které řešení nebo jaká kombinace řešení se pro vás a pro vaši organizaci hodí. diff --git a/cs/05-distributed-git/01-chapter5.markdown b/cs/05-distributed-git/01-chapter5.markdown index b4be707b8..da4cbf4b8 100644 --- a/cs/05-distributed-git/01-chapter5.markdown +++ b/cs/05-distributed-git/01-chapter5.markdown @@ -6,7 +6,7 @@ V této kapitole se dozvíte, jak pracovat se systémem Git v distribuovaném pr ## Distribuované pracovní postupy ## -Na rozdíl od centralizovaných systémů správy verzí (CVCS) umožňuje distribuovaný charakter systému Git mnohem větší flexibilitu při spolupráci vývojářů na projektech. V centralizovaných systémech představuje každý vývojář samostatný uzel, pracující více či méně na stejné úrovni vůči centrálnímu úložišti. Naproti tomu je v systému Git každý vývojář potenciálním uzlem i úložištěm, každý vývojář může přispívat kódem do jiných repozitářů i spravovat veřejný repozitář, na němž mohou ostatní založit svou práci a do nějž mohou přispívat. Tím se otvírá široké spektrum možností organizace práce pro váš projekt a/nebo váš tým. Zkusíme se tedy podívat na pár častých postupů, které tato flexibilita umožňuje. Uvedeme přednosti i eventuální slabiny všech těchto postupů. Budete si moci vybrat některý z postupů nebo je navzájem kombinovat a spojovat jejich funkce. +Na rozdíl od centralizovaných systémů správy verzí (CVCS) umožňuje distribuovaný charakter systému Git mnohem větší flexibilitu při spolupráci vývojářů na projektech. V centralizovaných systémech představuje každý vývojář samostatný uzel, pracující více či méně na stejné úrovni vůči centrálnímu úložišti. Naproti tomu je v systému Git každý vývojář potenciálním uzlem i úložištěm, každý vývojář může přispívat kódem do jiných repozitářů i spravovat veřejný repozitář, na němž mohou ostatní založit svou práci a do nějž mohou přispívat. Tím se pro váš projekt a váš tým otvírá široké spektrum pracovních postupů. Zkusíme se tedy podívat na pár častých přístupů, které tato flexibilita umožňuje. Uvedeme jejich přednosti i eventuální slabiny. Budete si moci vybrat některý z postupů nebo je navzájem kombinovat a spojovat jejich vlastnosti. ### Centralizovaný pracovní postup ### @@ -17,12 +17,12 @@ Obrázek 5-1. Centralizovaný pracovní postup To znamená, že pokud dva vývojáři klonují z centrálního úložiště a oba provedou změny, jen první z nich, který odešle své změny, to může provést bez komplikací. Druhý vývojář musí před odesláním svých změn začlenit práci prvního vývojáře do své, aby nepřepsal jeho změny. Tento koncept platí jak pro Git, tak pro Subversion (popř. jakýkoli CVCS). I v systému Git funguje bez problémů. -Pokud pracujete v malém týmu nebo už jste ve své společnosti nebo ve svém týmu zvyklí na centralizovaný pracovní postup, můžete v něm beze všeho pokračovat. Jednoduše vytvořte repozitář a přidělte všem ze svého týmu oprávnění k odesílání dat. Git neumožní uživatelům, aby se navzájem přepisovali. Pokud některý z vývojářů naklonuje data, provede změny a poté se je pokusí odeslat, a jiný vývojář mezitím odeslal svoje revize, server tyto změny odmítne. Git vývojáři při odmítnutí sdělí, že se pokouší odeslat změny, které nesměřují „rychle vpřed“, což není možné provést, dokud nevyzvedne a nezačlení stávající data z repozitáře. +Pokud pracujete v malém týmu nebo už jste ve své společnosti nebo ve svém týmu zvyklí na centralizovaný pracovní postup, můžete v něm beze všeho pokračovat. Jednoduše vytvořte repozitář a přidělte všem ze svého týmu oprávnění k odesílání dat. Git neumožní uživatelům, aby se navzájem přepisovali. Pokud některý z vývojářů naklonuje data, provede změny a poté se je pokusí odeslat, a jiný vývojář mezitím odeslal svoje revize, server tyto změny odmítne. Git vývojáři při odmítnutí sdělí, že se pokouší odeslat změny, které nesměřují „rychle vpřed“, což není možné provést, dokud nevyzvedne a nezačlení (fetch and merge) stávající data z repozitáře. Tento pracovní postup může být pro mnoho lidí zajímavý, protože je to schéma, které jsou zvyklí používat a jsou s ním spokojeni. ### Pracovní postup s integračním manažerem ### -Protože Git umožňuje, abyste měli několik vzdálených repozitářů, lze použít pracovní postup, kdy má každý vývojář oprávnění k zápisu do vlastního veřejného repozitáře a oprávnění pro čtení k repozitářům všech ostatních. Tento scénář často zahrnuje jeden standardní repozitář, který reprezentuje „oficiální“ projekt. Chcete-li do tohoto projektu přispívat, vytvořte vlastní veřejný klon projektu a odešlete do něj změny, které jste provedli. Poté odešlete správci hlavního projektu žádost, aby do projektu natáhl vaše změny. Váš repozitář může přidat jako vzdálený repozitář, lokálně otestovat vaše změny, začlenit je do své větve a odeslat zpět do svého repozitáře. Postup práce je následující (viz obrázek 5-2): +Protože Git umožňuje, abyste měli několik vzdálených repozitářů, lze použít pracovní postup, kdy má každý vývojář oprávnění k zápisu do vlastního veřejného repozitáře a oprávnění pro čtení k repozitářům všech ostatních. Tento scénář často zahrnuje jeden standardní repozitář, který reprezentuje „oficiální“ projekt. Chcete-li do tohoto projektu přispívat, vytvořte vlastní veřejný klon projektu a odešlete do něj změny, které jste provedli. Poté odešlete správci hlavního projektu žádost, aby do projektu natáhl vaše změny. Správce může váš repozitář přidat jako vzdálený repozitář, lokálně otestovat vaše změny, začlenit je do své větve a odeslat zpět do svého repozitáře. Postup práce je následující (viz obrázek 5-2): 1. Správce projektu odešle data do svého veřejného repozitáře. 2. Přispěvatel naklonuje tento repozitář a provede změny. @@ -34,7 +34,7 @@ Protože Git umožňuje, abyste měli několik vzdálených repozitářů, lze p Insert 18333fig0502.png Obrázek 5-2. Pracovní postup s integračním manažerem -Tento pracovní postup je velmi rozšířený na stránkách jako GitHub, kde je snadné rozštěpit projekt a odeslat změny do své odštěpené části, kde jsou pro každého k nahlédnutí. Jednou z hlavních předností tohoto postupu je, že můžete pracovat bez přerušení a správce hlavního repozitáře může natáhnout vaše změny do projektu, kdykoli uzná za vhodné. Přispěvatelé nemusí čekat, až budou jejich změny začleněny do projektu – každá strana může pracovat svým tempem. +Tento pracovní postup je velmi rozšířený na serverech jako je GitHub, kde je snadné rozštěpit projekt a odeslat změny do své odštěpené části, kde jsou pro každého k nahlédnutí. Jednou z hlavních předností tohoto postupu je, že můžete pracovat bez přerušení a správce hlavního repozitáře může natáhnout vaše změny do projektu, kdykoli uzná za vhodné. Přispěvatelé nemusí čekat, až budou jejich změny začleněny do projektu – každá strana může pracovat svým tempem. ### Pracovní postup s diktátorem a poručíky ### @@ -174,7 +174,7 @@ John má referenci ke změnám, které odeslala Jessica, ale než bude moci sám Sloučení probíhá hladce, Johnova historie revizí teď vypadá jako na obrázku 5-5. Insert 18333fig0505.png -Obrázek 5-5. Johnův repozitář po začlenění větve origin/master +Obrázek 5-5. Johnův repozitář po začlenění větve `origin/master` John nyní může otestovat svůj kód, aby se ujistil, že stále pracuje správně, a pak může odeslat svou novou sloučenou práci na server: @@ -215,7 +215,7 @@ Jessica považuje svou tematickou větev za dokončenou, ale chce vědět, do č removed invalid default value -Jessica nyní může začlenit tematickou větev do své hlavní větve, tamtéž začlenit i Johnovu práci (`origin/master`) do své větve `master` a vše odeslat zpět na server. Nejprve se přepne zpět na svou hlavní větev, aby do ní mohla vše integrovat: +Jessica nyní může začlenit tematickou větev do své větve `master`, začlenit (merge) i Johnovu práci (`origin/master`) do své větve `master` a vše odeslat zpět na server. Nejprve se přepne zpět na svou větev `master`, aby do ní mohla vše integrovat: $ git checkout master Switched to branch "master" @@ -255,7 +255,7 @@ Všichni vývojáři zapsali několik revizí a úspěšně začlenili práci os Insert 18333fig0510.png Obrázek 5-10. Historie Jessicy po odeslání všech změn zpět na server -Toto je jeden z nejjednodušších pracovních postupů. Po určitou dobu pracujete, obvykle na nějaké tematické větvi, a když je připravena k integraci, začleníte ji do hlavní větve. Chcete-li tuto práci sdílet, začleníte ji do své hlavní větve. Poté vyzvednete a začleníte větev `origin/master`, jestliže se změnila. Nakonec odešlete všechna data do větve `master` na serveru. Obecná posloupnost kroků je naznačena na obrázku 5-11. +Toto je jeden z nejjednodušších pracovních postupů. Po určitou dobu pracujete, obvykle na nějaké tematické větvi, a když je připravena k integraci, začleníte ji do své větve `master`. Chcete-li tuto práci sdílet, začleníte ji do své větve `master`. Poté vyzvednete (fetch) a začleníte (merge) větev `origin/master`, jestliže se změnila. Nakonec odešlete všechna data do větve `master` na serveru. Obecná posloupnost kroků je naznačena na obrázku 5-11. Insert 18333fig0511.png Obrázek 5-11. Obecná posloupnost kroků u jednoduchého pracovního postupu s více vývojáři v systému Git @@ -328,7 +328,7 @@ Tady nastává určitý problém. Musí odeslat práci začleněnou ve své vět To jessica@githost:simplegit.git fba9af8..cd685d1 featureB -> featureBee -Říká se tomu refspec. Více o vzorcích refspec systému Git a různých možnostech, k nimž je lze využít, najdete v kapitole 9. +Říká se tomu *refspec*. Více o vzorcích refspec systému Git a různých možnostech, k nimž je lze využít, najdete v kapitole 9. Poté pošle John Jessice e-mail, že odeslal několik změn do větve `featureA`, a poprosí ji, aby je ověřila. Jessica spustí příkaz `git fetch`, jímž tyto změny stáhne. @@ -532,7 +532,26 @@ Nejprve je třeba nastavit sekci „imap“ v souboru `~/.gitconfig`. Každou ho sslverify = false Pokud váš server IMAP nepoužívá SSL, dva poslední řádky zřejmě nebudou vůbec třeba a hodnota hostitele bude `imap://`, a nikoli `imaps://`. -Až toto nastavení dokončíte, můžete použít příkaz `git send-email`, jímž umístíte sérii patchů do složky Koncepty (Drafts) zadaného serveru IMAP: +Až toto nastavení dokončíte, můžete použít příkaz `git imap-send`, jímž umístíte sérii záplat (patch) do složky Koncepty (Drafts) zadaného serveru IMAP: + + $ cat *.patch |git imap-send + Resolving imap.gmail.com... ok + Connecting to [74.125.142.109]:993... ok + Logging in... + sending 2 messages + 100% (2/2) done + +V tomto okamžiku byste měli být schopni přejít do složky Drafts, změnit pole To na mailing list, do kterého záplatu posíláte, případně pole CC na správce nebo na osobu zodpovědnou za tuto část, a odeslat. + +Záplaty můžete odesílat i přes SMTP server. Stejně jako v předchozím případu můžete nastavit sérií příkazů `git config` každou hodnotu zvlášť, nebo je můžete vložit ručně do sekce sendemail souboru `~/.gitconfig`: + + [sendemail] + smtpencryption = tls + smtpserver = smtp.gmail.com + smtpuser = user@gmail.com + smtpserverport = 587 + +Jakmile je to hotové, můžete záplaty odeslat příkazem `git send-email`: $ git send-email *.patch 0001-added-limit-to-log-function.patch @@ -559,8 +578,6 @@ Git poté vytvoří log s určitými informacemi, který bude pro každou zápla Result: OK -V tomto okamžiku můžete přejít do své složky Koncepty, změnit pole Komu na adresáty z poštovní konference, jimž chcete záplatu odeslat, případně přidat kopii na správce nebo osobu odpovědnou za tuto část a e-mail odeslat. - ### Shrnutí ### V této části jsme popsali několik obvyklých pracovních postupů při přispívání do velmi odlišných typů projektů Git, s nimiž se můžete setkat. Představili jsme k nim také nové nástroje, které vám mohou v těchto procesech pomoci. V další části se na projekty podíváme z té druhé strany – ukážeme, jak může vypadat jejich správa. Dozvíte se, jak být benevolentním diktátorem nebo integračním manažerem. @@ -594,7 +611,7 @@ Pokud dostanete záplatu od někoho, kdo ji vygeneroval příkazem `git diff` ne Tím změníte soubory ve svém pracovním adresáři. Je to téměř stejné, jako byste k aplikaci záplaty použili příkaz `patch -p1`. Tento postup je však přísnější a nepřijímá tolik přibližných shod jako příkaz patch. Poradí si také s přidanými, odstraněnými a přejmenovanými soubory, jsou-li popsány ve formátu `git diff`, což příkaz `patch` nedělá. A konečně příkaz `git apply` pracuje na principu „aplikuj vše, nebo zruš vše“. Buď jsou tedy aplikovány všechny soubory, nebo žádný. Naproti tomu příkaz `patch` může aplikovat soubory záplaty jen částečně a zanechat váš pracovní adresář v neurčitém stavu. Příkaz `git apply` je tedy celkově víc paranoidní než příkaz `patch`. Tímto příkazem ostatně ani nezapíšete revizi, po jeho spuštění budete muset připravit a zapsat provedené změny ručně. -Příkaz git apply můžete použít také ke kontrole, zda bude záplata aplikována čistě. V takovém případě použijte na patch příkaz `git apply --check`: +Příkaz `git apply` můžete použít také ke kontrole, zda bude záplata aplikována čistě. V takovém případě použijte na patch příkaz `git apply --check`: $ git apply --check 0001-seeing-if-this-helps-the-gem.patch error: patch failed: ticgit.gemspec:1 @@ -615,7 +632,7 @@ K aplikaci patche vygenerovaného příkazem `format-patch` použijte příkaz ` Limit log functionality to the first 20 -Toto je začátek výstupu příkazu format-patch, s nímž jsme se setkali v předchozí části. Zároveň je to také platný e-mailový formát mbox. Jestliže vám přispěvatel řádně poslal záplatu e-mailem pomocí příkazu git send-email a vy záplatu stáhnete do formátu mbox, můžete na soubor mbox použít příkaz git am, který začne aplikovat všechny záplaty, které najde. Jestliže spustíte poštovního klienta, který dokáže uložit několik e-mailů ve formátu mbox, můžete do jednoho souboru uložit celou sérii záplat a příkazem git am je pak aplikovat všechny najednou. +Toto je začátek výstupu příkazu format-patch, s nímž jsme se setkali v předchozí části. Zároveň je to také platný e-mailový formát mbox. Jestliže vám přispěvatel řádně poslal záplatu e-mailem pomocí příkazu `git send-email` a vy záplatu stáhnete do formátu mbox, můžete na soubor mbox použít příkaz `git am`, který začne aplikovat všechny záplaty, které najde. Jestliže spustíte poštovního klienta, který dokáže uložit několik e-mailů ve formátu mbox, můžete do jednoho souboru uložit celou sérii záplat a příkazem `git am` je pak aplikovat všechny najednou. Pokud však někdo nahrál soubor záplaty vygenerovaný příkazem `format-patch` do tiketového nebo podobného systému, můžete soubor uložit lokálně a poté na tento uložený soubor použít příkaz `git am`. Tímto způsobem záplatu aplikujete: @@ -740,11 +757,11 @@ Můžete tedy explicitně najít společného předka obou větví a spustit na 36c7dba2c95e6bbb78dfa822519ecfec6e1ca649 $ git diff 36c7db -To však není příliš pohodlný způsob, a proto Git nabízí jinou možnost, jak lze provést stejnou věc: trojtečkovou syntax. V kontextu příkazu `diff` můžete vložit tři tečky za druhou větev – získáte výpis `diff` mezi poslední revizí větve, na níž se nacházíte, a společným předkem s druhou větví: +To však není příliš pohodlný způsob, a proto Git nabízí jinou možnost, jak lze provést stejnou věc: trojtečkovou syntaxi. V kontextu příkazu `diff` můžete vložit tři tečky za druhou větev – získáte výpis `diff` mezi poslední revizí větve, na níž se nacházíte, a společným předkem s druhou větví: $ git diff master...contrib -Tento příkaz zobrazí pouze práci, která byla ve vaší aktuální tematické větvi provedena od chvíle, kdy se oddělila od hlavní větve. Určitě uděláte dobře, pokud si tuto syntax zapamatujete. +Tento příkaz zobrazí pouze práci, která byla ve vaší aktuální tematické větvi provedena od chvíle, kdy se oddělila od hlavní větve. Určitě uděláte dobře, pokud si tuto syntaxi zapamatujete. ### Integrace příspěvků ### diff --git a/cs/06-git-tools/01-chapter6.markdown b/cs/06-git-tools/01-chapter6.markdown index 55eaa1bd3..24e5a12d3 100644 --- a/cs/06-git-tools/01-chapter6.markdown +++ b/cs/06-git-tools/01-chapter6.markdown @@ -59,7 +59,7 @@ Někteří uživatelé bývají zmateni, že mohou mít v repozitáři – shodo Pokud náhodou zapíšete objekt, který má stejnou hodnotu SHA-1 otisku jako předchozí objekt ve vašem repozitáři, Git už uvidí předchozí objekt v databázi Git a bude předpokládat, že už byl zapsán. Pokud se někdy v budoucnosti pokusíte znovu provést checkout tohoto objektu, vždy dostanete data prvního objektu. -Měli bychom však také říci, jak moc je nepravděpodobné, že taková situace nastane. Otisk SHA-1 má 20 bytů, neboli 160 bitů. Počet objektů s náhodným otiskem, které bychom potřebovali k 50% pravděpodobnosti, že nastane jediná kolize, je asi 280 (vzorec k určení pravděpodobnosti kolize je `p = (n(n-1)/2) * (1/2^160))`. 2^80 je 1,2 * 10^24, neboli 1 milion miliard miliard. To je 1200násobek počtu všech zrnek písku na celé Zemi. +Měli bychom však také říci, jak moc je nepravděpodobné, že taková situace nastane. Otisk SHA-1 má 20 bytů, neboli 160 bitů. Počet objektů s náhodným otiskem, které bychom potřebovali k 50% pravděpodobnosti, že nastane jediná kolize, je asi 2^80 (vzorec k určení pravděpodobnosti kolize je `p = (n(n-1)/2) * (1/2^160)`). 2^80 je 1,2 * 10^24, neboli 1 milion miliard miliard. To je 1200násobek počtu všech zrnek písku na celé Zemi. Abyste si udělali představu, jak je nepravděpodobné, že dojde ke kolizi hodnot SHA-1, připojujeme jeden malý příklad. Kdyby 6,5 miliardy lidí na zemi programovalo a každý by každou sekundu vytvořil kód odpovídající celé historii linuxového jádra (1 milion objektů Git) a odesílal ho do jednoho obřího repozitáře Git, trvalo by 5 let, než by repozitář obsahoval dost objektů na to, aby existovala 50% pravděpodobnost, že dojde ke kolizi jediného objektu SHA-1. To už je pravděpodobnější, že všichni členové vašeho programovacího týmu budou během jedné noci v navzájem nesouvisejících incidentech napadeni a zabiti smečkou vlků. @@ -82,19 +82,19 @@ Jednou z věcí, které probíhají na pozadí systému Git, zatímco vy pracuje Svůj reflog si můžete nechat zobrazit příkazem `git reflog`: $ git reflog - 734713b... HEAD@{0}: commit: fixed refs handling, added gc auto, updated - d921970... HEAD@{1}: merge phedders/rdocs: Merge made by recursive. - 1c002dd... HEAD@{2}: commit: added some blame and merge stuff - 1c36188... HEAD@{3}: rebase -i (squash): updating HEAD - 95df984... HEAD@{4}: commit: # This is a combination of two commits. - 1c36188... HEAD@{5}: rebase -i (squash): updating HEAD - 7e05da5... HEAD@{6}: rebase -i (pick): updating HEAD + 734713b HEAD@{0}: commit: fixed refs handling, added gc auto, updated + d921970 HEAD@{1}: merge phedders/rdocs: Merge made by recursive. + 1c002dd HEAD@{2}: commit: added some blame and merge stuff + 1c36188 HEAD@{3}: rebase -i (squash): updating HEAD + 95df984 HEAD@{4}: commit: # This is a combination of two commits. + 1c36188 HEAD@{5}: rebase -i (squash): updating HEAD + 7e05da5 HEAD@{6}: rebase -i (pick): updating HEAD Pokaždé, když je z nějakého důvodu aktualizován vrchol větve, Git tuto informaci uloží v dočasné historii reflog. Pomocí těchto dat lze rovněž specifikovat starší revize. Chcete-li zobrazit pátou poslední hodnotu ukazatele HEAD svého repozitáře, použijte referenci `@{n}` z výstupu reflog: $ git show HEAD@{5} -Tuto syntax můžete použít také k zobrazení pozice, na níž se větev nacházela před určitou dobou. Chcete-li například zjistit, kde byla vaše větev `master` včera (yesterday), můžete zadat příkaz: +Tuto syntaxi můžete použít také k zobrazení pozice, na níž se větev nacházela před určitou dobou. Chcete-li například zjistit, kde byla vaše větev `master` včera (yesterday), můžete zadat příkaz: $ git show master@{yesterday} @@ -146,7 +146,7 @@ Zobrazit předchozí revizi pak můžete pomocí `HEAD^`, což doslova znamená Merge commit 'phedders/rdocs' -Za znakem `^` můžete zadat také číslo, např. `d921970^2` označuje „druhého rodiče revize d921970“. Tato syntax má význam pouze u revizí vzniklých sloučením, které mají více než jednoho rodiče. První rodič je větev, na níž jste se během začlenění nacházeli, druhým rodičem je větev, kterou jste začleňovali: +Za znakem `^` můžete zadat také číslo, např. `d921970^2` označuje „druhého rodiče revize d921970“. Tato syntaxe má význam pouze u revizí vzniklých sloučením, které mají více než jednoho rodiče. První rodič je větev, na níž jste se během začlenění nacházeli, druhým rodičem je větev, kterou jste začleňovali: $ git show d921970^ commit 1c002dd4b536e7479fe34593e72e6c6c1819e53b @@ -188,7 +188,7 @@ Nyní, když umíte určit jednotlivé revize, podíváme se, jak lze určovat c #### Dvě tečky #### -Nejčastěji se při označení intervalu používá dvojtečková syntax. Pomocí ní systému Git v podstatě říkáte, aby uvažoval celý interval revizí, které jsou dostupné z jedné revize, ale nejsou dostupné z jiné. Předpokládejme tedy, že máte historii revizí jako na obrázku 6-1. +Nejčastěji se při označení intervalu používá dvojtečková syntaxe. Pomocí ní systému Git v podstatě říkáte, aby uvažoval celý interval revizí, které jsou dostupné z jedné revize, ale nejsou dostupné z jiné. Předpokládejme tedy, že máte historii revizí jako na obrázku 6-1. Insert 18333fig0601.png Obrázek 6-1. Příklad historie revizí pro výběr intervalu @@ -205,7 +205,7 @@ A samozřejmě si můžete nechat zobrazit i pravý opak, všechny revize ve vě F E -Tento log využijete, pokud chcete udržovat větev `experiment` stále aktuální a zjistit, co hodláte začlenit. Tato syntax se velmi často používá také ke zjištění, co hodláte odeslat do vzdálené větve: +Tento log využijete, pokud chcete udržovat větev `experiment` stále aktuální a zjistit, co hodláte začlenit. Tato syntaxe se velmi často používá také ke zjištění, co hodláte odeslat do vzdálené větve: $ git log origin/master..HEAD @@ -214,13 +214,13 @@ Jednu stranu intervalu můžete zcela vynechat, Git na její místo automaticky #### Několik bodů #### -Dvojtečková syntax je užitečná jako zkrácený výraz. Možná ale budete chtít k označení revize určit více než dvě větve, např. až budete chtít zjistit, které revize jsou obsaženy ve všech ostatních větvích a zároveň nejsou obsaženy ve větvi, na níž se právě nacházíte. V systému Git to můžete provést buď zadáním znaku `^` nebo parametru `--not` před referencí, jejíž dostupné revize si nepřejete zobrazit. Tyto tři příkazy jsou tedy ekvivalentní: +Dvojtečková syntaxe je užitečná jako zkrácený výraz. Možná ale budete chtít k označení revize určit více než dvě větve, např. až budete chtít zjistit, které revize jsou obsaženy ve všech ostatních větvích a zároveň nejsou obsaženy ve větvi, na níž se právě nacházíte. V systému Git to můžete provést buď zadáním znaku `^` nebo parametru `--not` před referencí, jejíž dostupné revize si nepřejete zobrazit. Tyto tři příkazy jsou tedy ekvivalentní: $ git log refA..refB $ git log ^refA refB $ git log refB --not refA -Tato syntax je užitečná zejména proto, že pomocí ní můžete zadat více než dvě reference, což není pomocí dvojtečkové syntaxe možné. Pokud chcete zobrazit například všechny revize, které jsou dostupné ve větvi `refA` nebo `refB`, ale nikoli ve větvi `refC`, zadejte jeden z následujících příkazů: +Tato syntaxe je užitečná zejména proto, že pomocí ní můžete zadat více než dvě reference, což není pomocí dvojtečkové syntaxe možné. Pokud chcete zobrazit například všechny revize, které jsou dostupné ve větvi `refA` nebo `refB`, ale nikoli ve větvi `refC`, zadejte jeden z následujících příkazů: $ git log refA refB ^refC $ git log refA refB --not refC @@ -229,7 +229,7 @@ Tím máte v rukou velmi efektivní systém vyhledávání revizí, který vám #### Tři tečky #### -Poslední významnou syntaxí k určení intervalu je trojtečková syntax, která vybere všechny revize dostupné ve dvou referencích, ale ne v obou zároveň. Podívejme se ještě jednou na příklad historie revizí na obrázku 6-1. +Poslední významnou syntaxí k určení intervalu je trojtečková syntaxe, která vybere všechny revize dostupné ve dvou referencích, ale ne v obou zároveň. Podívejme se ještě jednou na příklad historie revizí na obrázku 6-1. Chcete-li zjistit, co je ve větvi `master` nebo `experiment`, ale nechcete vidět jejich společné reference, zadejte příkaz: $ git log master...experiment @@ -457,14 +457,14 @@ Váš pracovní adresář se vyčistil: $ git status # On branch master - nothing to commit (working directory clean) + nothing to commit, working directory clean Nyní můžete bez obav přepnout větve a pracovat na jiném úkolu, vaše změny byly uloženy do zásobníku. Chcete-li se podívat, které soubory jste odložili, spusťte příkaz `git stash list`: $ git stash list stash@{0}: WIP on master: 049d078 added the index file - stash@{1}: WIP on master: c264051... Revert "added file_size" - stash@{2}: WIP on master: 21d80a5... added number to log + stash@{1}: WIP on master: c264051 Revert "added file_size" + stash@{2}: WIP on master: 21d80a5 added number to log V tomto případě byly už dříve provedeny dva další odklady, a máte tak k dispozici tři různé odklady. Naposledy odložené soubory můžete znovu aplikovat příkazem, který byl uveden už v nápovědě ve výstupu původního příkazu stash: `git stash apply`. Chcete-li aplikovat některý ze starších odkladů, můžete ho určit na základě jeho označení, např. `git stash apply stash@{2}`. Pokud u příkazu neoznačíte konkrétní odklad, Git se automaticky pokusí aplikovat ten nejnovější: @@ -498,8 +498,8 @@ Parametr apply se pouze pokusí aplikovat odloženou práci, ta zůstává ulož $ git stash list stash@{0}: WIP on master: 049d078 added the index file - stash@{1}: WIP on master: c264051... Revert "added file_size" - stash@{2}: WIP on master: 21d80a5... added number to log + stash@{1}: WIP on master: c264051 Revert "added file_size" + stash@{2}: WIP on master: 21d80a5 added number to log $ git stash drop stash@{0} Dropped stash@{0} (364e91f3f268f0900bc3ee613f9f733e82aaed43) @@ -518,7 +518,7 @@ Jestliže nespecifikujete konkrétní odklad, Git předpokládá odklad posledn Můžete si také vytvořit alias a do svého gitu přidat například příkaz `stash-unapply`: $ git config --global alias.stash-unapply '!git stash show -p | git apply -R' - $ git stash + $ git stash apply $ #... work work work $ git stash-unapply @@ -583,12 +583,19 @@ Spuštěním tohoto příkazu otevřete textový editor se seznamem revizí zhru # # Commands: # p, pick = use commit + # r, reword = use commit, but edit the commit message # e, edit = use commit, but stop for amending # s, squash = use commit, but meld into previous commit + # f, fixup = like "squash", but discard this commit's log message + # x, exec = run command (the rest of the line) using shell + # + # These lines can be re-ordered; they are executed from top to bottom. # # If you remove a line here THAT COMMIT WILL BE LOST. + # # However, if you remove everything, the rebase will be aborted. # + # Note that empty commits are commented out Tady bychom chtěli upozornit, že revize jsou uvedeny v opačném pořadí, než jste zvyklí v případě příkazu `log`. Po spuštění příkazu `log` by se zobrazilo následující: @@ -607,6 +614,10 @@ Skript je třeba upravit tak, aby zastavil na revizi, v níž chcete provést zm Po uložení změn a zavření editoru vás Git vrátí zpět na poslední revizi v seznamu a zobrazí vám příkazový řádek s touto zprávou: + + $ git rebase -i HEAD~3 Stopped at 7482e0d... updated the gemspec to hopefully work better You can amend the commit now, with @@ -649,12 +660,19 @@ Další možností, jak lze využít interaktivního nástroje přeskládání, # # Commands: # p, pick = use commit + # r, reword = use commit, but edit the commit message # e, edit = use commit, but stop for amending # s, squash = use commit, but meld into previous commit + # f, fixup = like "squash", but discard this commit's log message + # x, exec = run command (the rest of the line) using shell + # + # These lines can be re-ordered; they are executed from top to bottom. # # If you remove a line here THAT COMMIT WILL BE LOST. + # # However, if you remove everything, the rebase will be aborted. # + # Note that empty commits are commented out Zadáte-li místo pick nebo edit instrukci pro komprimaci squash, Git aplikuje změnu na tomto řádku a změnu těsně před ní a zároveň sloučí dohromady obě zprávy k revizím. Chcete-li tedy vytvořit jedinou revizi z těchto tří revizí, bude skript vypadat takto: @@ -747,6 +765,12 @@ Dalším častým případem bývá, že uživatel zapomene spustit příkaz `gi Příkaz projde a přepíše všechny revize tak, aby obsahovaly novou adresu. Protože revize obsahují hodnoty SHA-1 svých rodičů, změní tento příkaz SHA všech revizí ve vaší historii, ne pouze těch, které mají odpovídající e-mailovou adresu. +### Velmi rychlá a nebezpečná zbraň: Big Friendly Giant Repo Cleaner (BFG) ### + +[Roberto Tyley](https://github.com/rtyley) vytvořil nástroj, který se funkčností podobá `filter-branch` a nazval jej BFG. (Celý název lze doslova přeložit jako Velký, přátelský, obří čistič repozitáře --- představte si pod tím, co chcete.) BFG neumí tolik věcí jako `filter-branch`, ale je *velmi* rychlý. Pro velké repozitáře to může být zásadní rozdíl. Pokud lze vámi zamýšlenou změnu pomocí BFG provést a pokud máte problémy s výkonností prostředí, pak byste o použití tohoto nástroje měli uvažovat. + +Podrobnosti naleznete na stránkách [BFG](http://rtyley.github.io/bfg-repo-cleaner/). + ## Ladění v systému Git ## Git také nabízí několik nástrojů, které vám pomohou ladit problémy v projektech. Protože je Git navržen tak, aby pracoval téměř s jakýmkoli typem projektu, jsou tyto nástroje velmi univerzální. Často vám mohou pomoci odhalit vzniklou chybu nebo problém. @@ -1014,7 +1038,7 @@ Dobrým způsobem, jak to v systému Git provést, je učinit ze všech podslož ### Problémy se submoduly ### -Používání submodulů se však vždy neobejde bez zádrhelů. Zaprvé je třeba, abyste si v adresáři submodulu počínali opatrně. Spustíte-li příkaz `git submodule update`, provedete tím checkout konkrétní verze projektu, avšak nikoli v rámci větve. Říká se tomu oddělená hlava (detached head) – znamená to, že soubor HEAD ukazuje přímo na revizi, ne na symbolickou referenci. Problém je, že většinou nechcete pracovat v prostředí oddělené hlavy, protože tu velmi snadno přijdete o provedené změny. Jestliže nejprve spustíte příkaz `submodule update`, zapíšete v adresáři tohoto submodulu revizi, aniž byste na tuto práci vytvořili novou větev, a poté ze superprojektu znovu spustíte příkaz `git submodule update`, aniž byste mezitím zapisovali revize, Git vaše revize bez varování přepíše. Technicky vzato práci neztratíte, ale nebude žádná větev, která by na ni ukazovala, a tak bude poněkud obtížené získat práci zpět. +Používání submodulů se však vždy neobejde bez zádrhelů. Zaprvé je třeba, abyste si v adresáři submodulu počínali opatrně. Spustíte-li příkaz `git submodule update`, provedete tím checkout konkrétní verze projektu, avšak nikoli v rámci větve. Říká se tomu oddělená hlava (detached head) – znamená to, že soubor HEAD ukazuje přímo na revizi, ne na symbolickou referenci. Problém je, že většinou nechcete pracovat v prostředí oddělené hlavy, protože byste tak velmi snadno mohli přijít o provedené změny. Jestliže nejprve spustíte příkaz `submodule update`, zapíšete v adresáři tohoto submodulu revizi, aniž byste na tuto práci vytvořili novou větev, a poté ze superprojektu znovu spustíte příkaz `git submodule update`, aniž byste mezitím zapisovali revize, Git vaše revize bez varování přepíše. Technicky vzato práci neztratíte, ale nebude žádná větev, která by na ni ukazovala, a tak bude poněkud obtížené získat práci zpět. Aby ve vašem projektu k tomuto problému nedošlo, vytvořte během práce v adresáři submodulu příkazem `git checkout -b work` nebo podobným novou větev. Až budete podruhé provádět příkaz submodule update, i tentokrát sice vrátí vaši práci, ale přinejmenším budete mít ukazatel, k němuž se budete moci vrátit. @@ -1077,9 +1101,9 @@ Až poté přepnete zpět, bude adresář `rack` prázdný. Buď můžete spusti ## Začlenění podstromu ## -Nyní, když jsme poznali obtíže spojené se systémem submodulů, podívejme se na jedno alternativní řešení tohoto problému. Git se vždy při slučování nejprve podívá, co a kam začleňuje, a podle toho zvolí vhodnou strategii začlenění. Pokud slučujete dvě větve, používá Git rekurzivní strategii. Pokud slučujete více než dvě větve, zvolí Git tzv. strategii chobotnice (octopus strategy). Git vybírá tyto strategie automaticky. Rekurzivní strategie zvládá složité třícestné slučování (např. s více než jedním společným předkem), ale nedokáže sloučit více než dvě větve. Chobotnicové sloučení dokáže naproti tomu sloučit několik větví, ale je opatrnější při předcházení složitým konfliktům. Proto je ostatně nastaveno jako výchozí strategie při slučování více než dvou větví. +Nyní, když jsme poznali obtíže spojené se systémem submodulů, podívejme se na jedno alternativní řešení tohoto problému. Git se vždy při slučování nejprve podívá, co a kam začleňuje, a podle toho zvolí vhodnou strategii začlenění. Pokud slučujete dvě větve, používá Git *rekurzivní* strategii. Pokud slučujete více než dvě větve, zvolí Git tzv. strategii *chobotnice* (octopus strategy). Git vybírá tyto strategie automaticky. Rekurzivní strategie zvládá složité třícestné slučování (např. s více než jedním společným předkem), ale nedokáže sloučit více než dvě větve. Chobotnicové sloučení dokáže naproti tomu sloučit několik větví, ale je opatrnější při předcházení složitým konfliktům. Proto je ostatně nastaveno jako výchozí strategie při slučování více než dvou větví. -Existují však ještě další strategie. Jednou z nich je tzv. začlenění podstromu (subtree merge), které lze použít jako řešení problémů se subprojektem. Ukažme si, jak se dá začlenit stejný adresář rack jako v předchozí části, tentokrát však s využitím strategie začlenění podstromu. +Existují však ještě další strategie. Jednou z nich je tzv. začlenění *podstromu* (subtree merge), které lze použít jako řešení problémů se subprojektem. Ukažme si, jak se dá začlenit stejný adresář rack jako v předchozí části, tentokrát však s využitím strategie začlenění podstromu. Začlenění podstromu spočívá v tom, že máte dva projekty a jeden z projektů se promítá do podadresáře druhého projektu a naopak. Pokud určíte strategii začlenění podstromu, je Git natolik inteligentní, aby zjistil, že je jeden podstromem druhého, a provedl sloučení odpovídajícím způsobem – počíná si opravdu sofistikovaně. @@ -1112,7 +1136,7 @@ Nyní máte kořenový adresář s projektem Rack ve větvi `rack_branch` a vlas $ ls README -Projekt Rack chcete do projektu `master` natáhnout jako podadresář. V systému Git k tomu slouží příkaz `git read-tree`. O příkazu `read-tree` a jeho příbuzných se více dočtete v kapitole 9, nyní však vězte, že načte kořenový strom jedné větve do vaší aktuální oblasti připravených změn a do pracovního adresáře. Přepnuli jste zpět na větev `master` a větev `rack` natáhnete do podadresáře `rack` své větve `master` hlavního projektu: +Projekt Rack chcete do projektu `master` natáhnout jako podadresář. V systému Git k tomu slouží příkaz `git read-tree`. O příkazu `read-tree` a jeho příbuzných se více dočtete v kapitole 9, nyní však vězte, že načte kořenový strom jedné větve do vaší aktuální oblasti připravených změn a do pracovního adresáře. Přepnuli jste zpět na větev `master` a větev `rack_branch` natáhnete do podadresáře `rack` své větve `master` hlavního projektu: $ git read-tree --prefix=rack/ -u rack_branch diff --git a/cs/07-customizing-git/01-chapter7.markdown b/cs/07-customizing-git/01-chapter7.markdown index ad1bb57d0..e910b46f3 100644 --- a/cs/07-customizing-git/01-chapter7.markdown +++ b/cs/07-customizing-git/01-chapter7.markdown @@ -130,7 +130,7 @@ Chcete-li sami nastavit jednotlivé barvy, mají všechny tyto parametry navíc $ git config --global color.diff.meta "blue black bold" -U barev lze zadávat tyto hodnoty: normal (normální), black (černá), red (červená), green (zelená), yellow (žlutá), blue (modrá), magenta (purpurová), cyan (azurová) nebo white (bílá). Pokud chcete použít atribut, jakým bylo v předchozím příkladu například tučné písmo, můžete vybírat mezi bold (tučné), dim (tlumené), ul (podtržené), blink (blikající) a reverse (obrácené). +U barev lze zadávat tyto hodnoty: `normal` (normální), `black` (černá), `red` (červená), `green` (zelená), `yellow` (žlutá), `blue` (modrá), `magenta` (purpurová), `cyan` (azurová) nebo `white` (bílá). Pokud chcete použít atribut, jakým bylo v předchozím příkladu například tučné písmo, můžete vybírat mezi `bold` (tučné), `dim` (tlumené), `ul` (podtržené), `blink` (blikající) a `reverse` (obrácené). Chcete-li použít dílčí nastavení, podrobnější informace naleznete na manuálové stránce `git config`. @@ -142,7 +142,7 @@ Pokud ho chcete vyzkoušet, nemělo by vám v tom nic bránit, P4Merge funguje n P4Merge můžete stáhnout na této adrese: - http://www.perforce.com/perforce/downloads/component.html + http://www.perforce.com/product/components/perforce-visual-merge-and-diff-tools Pro začátek je třeba nastavit kvůli spouštění příkazů externí skripty wrapperu. Jako cestu ke spustitelnému souboru používám cestu v systému Mac. V ostatních systémech použijte cestu k umístění, kde máte nainstalován binární soubor `p4merge`. Nastavte wrapperový skript pro slučování `extMerge`, který bude volat binární soubor všemi dostupnými parametry: @@ -301,17 +301,21 @@ Chcete-li systému Git zadat, aby nakládal se všemi soubory `pbxproj` jako s b *.pbxproj -crlf -diff -Až v projektu spustíte příkaz git show nebo git diff, Git se nebude pokoušet konvertovat nebo opravovat chyby CRLF ani vypočítat ani zobrazit rozdíly v tomto souboru pomocí nástroje diff. V systému Git verze 1.6 můžete také použít existující makro s významem `-crlf -diff`: +Až v projektu spustíte příkaz `git show` nebo `git diff`, Git se nebude pokoušet konvertovat nebo opravovat chyby CRLF ani vypočítat ani zobrazit rozdíly v tomto souboru pomocí nástroje diff. Můžete také použít zabudované makro `binary` s významem `-crlf -diff`: *.pbxproj binary #### Nástroj diff pro binární soubory #### -Ve verzi 1.6 systému Git můžete použít funkci atributů Git k efektivnímu zpracování binárních souborů nástrojem diff. Systému Git přitom sdělíte, jak má konvertovat binární data do textového formátu, který lze zpracovávat běžným nástrojem diff. +V systému Git můžete zadáním vhodných parametrů efektivně porovnávat binární soubory. Dosáhnete toho tím, že systému Git sdělíte, jak má konvertovat binární data do textového formátu, který lze zpracovávat běžným algoritmem pro zjišťování rozdílů (diff). Ale otázkou je, jak byste měli konverzi *binárních* dat na text provést? Nejlepší by bylo, kdybyste našli nějaký nástroj, který vám binární tvar na textový převede. Naneštěstí existuje jen velmi málo binárních formátů, které lze převést na lidsky čitelný text. (Představte si, jak byste na text převáděli zvuková data.) Pokud takový případ nastal a nejste schopni textovou reprezentaci obsahu souboru získat, lze často poměrně snadno získat lidsky čitelný popis obsahu, metadata. Metadata vám sice neposkytnou plnou reprezentaci obsahu souboru, ale v každém případě je to lepší než nic. + +Oba popsané přístupy k získání použitelných informací o rozdílech si ukážeme na některých běžně používaných binárních formátech. + +Poznámka: Existují různé druhy binárních formátů, které obsahují text, a pro které se dají obtížně najít použitelné konvertory. V takovém případě můžete zkusit získat z vašeho souboru texty programem `strings`. Některé z těchto souborů ale mohou používat kódování UTF-16 nebo jiné kódování a `strings` v nich nic rozumného nenajde. Je to případ od případu. Nicméně program `strings` je k dispozici na většině operačních systémů Mac a Linux, takže může jít o dobrou první volbu při pokusech s celou řadou binárních souborů. #### Soubory MS Word #### -Protože se jedná o opravdu šikovnou a nepříliš známou funkci, uvedu několik příkladů. Tuto metodu budete využívat především k řešení jednoho z nejpalčivějších problémů, s nímž se lidstvo potýká: verzování dokumentů Word. Je všeobecně známo, že Word je nejpříšejnější editor na světě, přesto ho však – bůhví proč – všichni používají. Chcete-li verzovat dokumenty Word, můžete je uložit do repozitáře Git a všechny hned zapsat do revize. K čemu to však bude? Spustíte-li příkaz `git diff` normálně, zobrazí se zhruba toto: +Tuto metodu budete využívat především k řešení jednoho z nejpalčivějších problémů, s nímž se lidstvo potýká: verzování dokumentů Word. Je všeobecně známo, že Word je nejpříšernější editor na světě, přesto ho však – bůhví proč – všichni používají. Chcete-li verzovat dokumenty Word, můžete je uložit do repozitáře Git a všechny hned zapsat do revize. K čemu to však bude? Spustíte-li příkaz `git diff` normálně, zobrazí se zhruba toto: $ git diff diff --git a/chapter1.doc b/chapter1.doc @@ -322,18 +326,16 @@ Srovnávat dvě verze přímo nelze, můžete je tak nanejvýš otevřít a ruč *.doc diff=word -Systému Git tím sdělíte, že pro všechny soubory, které odpovídají této masce (.doc), by měl být při zobrazení rozdílů použít filter word. Co je to filtr „word“? To budete muset nastavit. V našem případě nastavíme Git tak, aby ke konverzi dokumentů Word do čitelných textových souborů, způsobilých ke zpracování nástrojem diff, používal program `strings`: +Systému Git tím sdělíte, že pro všechny soubory, které odpovídají této masce (.doc), by měl být při zobrazení rozdílů použít filter „word“. Co je to filtr „word“? To budete muset nastavit. V našem případě nastavíme Git tak, aby ke konverzi dokumentů Word do čitelných textových souborů, způsobilých ke zpracování nástrojem diff, používal program `catdoc`, který byl napsán přímo pro extrakci textu z binární podoby dokumentů MS Word (můžete jej získat z `http://www.wagner.pp.ru/~vitus/software/catdoc/`). Tím wordovské dokumenty převedeme na čitelné textové soubory, na které lze úspěšně aplikovat algoritmus pro zjišťování rozdílů (diff): - $ git config diff.word.textconv strings + $ git config diff.word.textconv catdoc Tento příkaz do vašeho `.git/config` přidá sekci, která vypadá následovně: [diff "word"] - textconv = strings + textconv = catdoc -Okrajová poznámka: Existují různé druhy `.doc` souborů. Některé používají kódování UTF-16 nebo jiné kódové stránky a `strings` v nich nic rozumného nenajde. Záleží na okolnostech. - -Git nyní ví, že až se bude pokoušet vypočítat rozdíl mezi dvěma snímky a jeden ze souborů bude končit na `.doc`, má tyto soubory spustit přes filtr word, který je definován jako program `strings`. Než se Git pokusí porovnat soubory Word nástrojem diff, efektivně vytvoří hezké textové verze souborů. +Git nyní ví, že až se bude pokoušet vypočítat rozdíl mezi dvěma snímky a každý ze souborů končící na `.doc` se má prohnat přes filtr „word“, který je definován jako program `catdoc`. Než se Git pokusí zjistit ve wordovských souborech rozdíly, dojde k jejich převedení na hezké textové verze. Uveďme malý příklad. Kapitolu 1 této knihy jsem vložil do systému Git, do jednoho odstavce jsem přidal kousek textu a dokument jsem uložil. Poté jsem spustil příkaz `git diff`, abych se podíval, co se změnilo: @@ -342,19 +344,18 @@ Uveďme malý příklad. Kapitolu 1 této knihy jsem vložil do systému Git, do index c1c8a0a..b93c9e4 100644 --- a/chapter1.doc +++ b/chapter1.doc - @@ -8,7 +8,8 @@ re going to cover Version Control Systems (VCS) and Git basics - re going to cover how to get it and set it up for the first time if you don - t already have it on your system. - In Chapter Two we will go over basic Git usage - how to use Git for the 80% - -s going on, modify stuff and contribute changes. If the book spontaneously - +s going on, modify stuff and contribute changes. If the book spontaneously - +Let's see if this works. + @@ -128,7 +128,7 @@ and data size) + Since its birth in 2005, Git has evolved and matured to be easy to use + and yet retain these initial qualities. It’s incredibly fast, it’s + very efficient with large projects, and it has an incredible branching + -system for non-linear development. + +system for non-linear development (See Chapter 3). -Git mi stroze, ale pravdivě sděluje, že jsem přidal řetězec „Let’s see if this works“. Není to sice dokonalé – na konci je přidáno několik náhodných znaků – ale evidentně to funguje. Pokud se vám podaří najít či vytvořit dobře fungující převaděč dokumentů Word na prostý text, bude toto řešení bezpochyby velmi účinné. Program `strings` je však k dispozici ve většině systémů Mac i Linux, a tak možná nejprve vyzkoušejte tento program s různými binárními formáty. +Git mi stroze, ale pravdivě sděluje, že jsem přidal řetězec „(See Chapter 3)“, což je správné. Funguje to perfektně! ##### OpenDocument Text files ##### -Stejný postup, který jsme použili pro soubory MS Word (`*.doc`), můžeme použít i pro soubory ve formátu OpenDocument Text (`*.odt`), kter vytváří OpenOffice.org. +Stejný postup, který jsme použili pro soubory MS Word (`*.doc`), můžeme použít i pro soubory ve formátu OpenDocument Text (`*.odt`), které vytváří OpenOffice.org. Do souboru `.gitattributes` přidejte následující řádek: @@ -459,7 +460,7 @@ Obrázek 7-2. Filtr smudge spuštěný při checkoutu – git checkout Insert 18333fig0703.png Obrázek 7-3. Filtr clean spuštěný při přípravě souborů k zapsání – git add -Původní zpráva k revizi s touto funkcí uvádí jednoduchý příklad, jak můžete před zapsáním prohnat veškeré vaše céčkové zdrojové texty programem `indent`. Tuto možnost lze aplikovat nastavením atributu `filter` v souboru `.gitattributes` tak, aby přefiltroval soubory `*.c` filtrem pro úpravu odsazování: +Původní zpráva k revizi s touto funkcí uvádí jednoduchý příklad, jak můžete před zapsáním prohnat veškeré vaše céčkové zdrojové texty programem `indent`. V souboru `.gitattributes` můžeme nastavit atribut `filter` tak, aby se soubory `*.c` zpracovaly filtrem `indent`: *.c filter=indent @@ -510,7 +511,7 @@ Systému Git můžete zadat, aby při generování archivu neexportoval určité test/ export-ignore -Až nyní spustíte příkaz git archive k vytvoření tarballu projektu, nebude tento adresář součástí archivu. +Až nyní spustíte příkaz `git archive` k vytvoření tarballu projektu, nebude tento adresář součástí archivu. #### export-subst #### @@ -530,10 +531,14 @@ Spustíte-li příkaz `git archive`, bude po otevření soubor archivu vypadat o Atributy Git lze použít také k nastavení různých strategií slučování pro různé soubory v projektu. Velmi užitečnou možností je například nastavení, aby se Git nepokoušel sloučit konkrétní soubory, pokud u nich dojde ke konfliktu, a raději použil vaši verzi souboru než jinou. -Tuto možnost využijete, pokud se rozdělila nebo specializovala některá z větví vašeho projektu, avšak vy z ní budete chtít začlenit změny zpět a ignorovat přitom určité soubory. Řekněme, že máte soubor s nastavením databáze database.xml, který se ve dvou větvích liší, a vy sem chcete začlenit jinou svoji větev, aniž byste tento soubor změnili. V tom případě můžete nastavit tento atribut: +Tuto možnost využijete, pokud se rozdělila nebo specializovala některá z větví vašeho projektu, avšak vy z ní budete chtít začlenit změny zpět a ignorovat přitom určité soubory. Řekněme, že máte soubor s nastavením databáze nazvaný database.xml, který se ve dvou větvích liší, a vy sem chcete začlenit jinou svoji větev, aniž byste tento soubor změnili. V tom případě můžete nastavit tento atribut: database.xml merge=ours +A potom nadefinujete prázdnou slučovací strategii `ours` příkazem: + + git config --global merge.ours.driver true + Pokud začleníte druhou větev, místo řešení konfliktů u souboru database.xml se zobrazí následující: $ git merge topic @@ -600,7 +605,7 @@ Zásuvný modul `post-receive` se spouští až poté, co je celý proces dokon Skript update je velice podobný skriptu `pre-receive`, avšak s tím rozdílem, že se spouští zvlášť pro každou větev, kterou chce odesílatel aktualizovat. Pokud se uživatel pokouší odeslat revize do více větví, skript `pre-receive` se spustí pouze jednou, zatímco update se spustí jednou pro každou větev, již se odesílatel pokouší aktualizovat. Tento skript nenačítá data ze standardního vstupu, místo nich používá tři jiné parametry: název reference (větve), hodnotu SHA-1, na niž reference ukazovala před odesláním, a hodnotu SHA-1, kterou se uživatel pokouší odeslat. Je-li výstup skriptu update nenulový, je zamítnuta pouze tato reference, ostatní mohou být aktualizovány. -## Příklad standardů kontrolovaných systémem Git ## +## Příklad vynucení chování systémem Git ## V této části použijeme to, co jsme se naučili o vytváření pracovního postupu v systému Git. Systém může kontrolovat formát uživatelovy zprávy k revizi, dovolit pouze aktualizace „rychle vpřed“ a umožňovat změnu obsahu konkrétních podadresářů projektu pouze vybraným uživatelům. V této části vytvoříte skripty pro klienta, které vývojářům pomohou zjistit, zda budou jejich revize odmítnuty, a skripty na server, které si specifikované požadavky přímo vynutí. @@ -612,14 +617,12 @@ Veškerá práce na straně serveru bude uložena do souboru update v adresáři #!/usr/bin/env ruby - $refname = ARGV[0] - $oldrev = ARGV[1] - $newrev = ARGV[2] - $user = ENV['USER'] - - puts "Enforcing Policies... \n(#{$refname}) (#{$oldrev[0,6]}) (#{$newrev[0,6]})" + refname = ARGV[0] + oldrev = ARGV[1] + newrev = ARGV[2] + user = ENV['USER'] -Ano, je to tak, používám globální proměnné. Ale neodsuzujte mne – náš příklad díky tomu bude názornější. + puts "Enforcing Policies... \n(#{refname}) (#{oldrev[0,6]}) (#{newrev[0,6]})" #### Standardizovaná zpráva k revizi #### @@ -924,11 +927,11 @@ Jako příklad uvedeme skript pre-rebase, který bude toto pravidlo kontrolovat. end end -Tento skript používá syntax, které jsme se v části Výběr revize v kapitole 6 nevěnovali. Seznam revizí, které už byly odeslány, získáte takto: +Tento skript používá syntaxi, které jsme se v části Výběr revize v kapitole 6 nevěnovali. Seznam revizí, které už byly odeslány, získáte takto: git rev-list ^#{sha}^@ refs/remotes/#{remote_ref} -Syntax `SHA^@` se vztahuje na všechny rodiče této revize. Vyhledáváte všechny revize, které jsou dostupné z poslední revize na vzdáleném serveru a nejsou dostupné z žádného rodiče jakékoli hodnoty SHA, kterou se pokoušíte odeslat. Tímto způsobem lze označit odeslání „rychle vpřed“. +Syntaxe `SHA^@` se vztahuje na všechny rodiče této revize. Vyhledáváte všechny revize, které jsou dostupné z poslední revize na vzdáleném serveru a nejsou dostupné z žádného rodiče jakékoli hodnoty SHA, kterou se pokoušíte odeslat. Tímto způsobem lze označit odeslání „rychle vpřed“. Největší nevýhodou tohoto postupu je, že může být velmi pomalý a není vždy nutný. Pokud se nesnažíte vynutit si odeslání parametrem `-f`, server vás sám upozorní a odesílané revize nepřijme. Skript je však zajímavým cvičením a teoreticky vám může pomoci předejít nutnosti vracet se v historii a přeskládávat revize kvůli opravě chyby. diff --git a/cs/08-git-and-other-scms/01-chapter8.markdown b/cs/08-git-and-other-scms/01-chapter8.markdown index b12839ae7..303db4d2f 100644 --- a/cs/08-git-and-other-scms/01-chapter8.markdown +++ b/cs/08-git-and-other-scms/01-chapter8.markdown @@ -87,7 +87,7 @@ V tomto okamžiku byste tedy měli mít platný repozitář Git s importovanými tags/release-2.0.2rc1 trunk -Doplňme také, že tento nástroj odlišně přiřazuje jmenný prostor vzdálených referencí. Jestliže klonujete normální repozitář Git, získáte ze vzdáleného serveru všechny větve, lokálně dostupné pod označením `origin/[větev]` – jmenný prostor se přiřazuje na základě vzdáleného serveru. `git svn` však předpokládá, že nebudete mít více vzdálených repozitářů a všechny reference uloží na místa na vzdáleném serveru bez jmenného prostoru. Pokud si přejete zobrazit všechny své reference s úplným názvem, můžete použít nízkoúrovňový příkaz `show-ref`: +Doplňme také, že tento nástroj odlišně přiřazuje jmenný prostor vzdálených referencí. Jestliže klonujete normální repozitář Git, získáte ze vzdáleného serveru všechny větve, lokálně dostupné pod označením `origin/[větev]` – jmenný prostor je dán jménem vzdáleného serveru. Příkaz `git svn` však předpokládá, že nebudete mít více vzdálených repozitářů a všechny odkazy na místa na vzdáleném serveru uloží bez použití jmenného prostoru. Pokud si přejete zobrazit všechny své reference s úplným názvem, můžete použít nízkoúrovňový příkaz `show-ref`: $ git show-ref 1cbd4904d9982f386d87f88fce1c24ad7c0f0471 refs/heads/master @@ -202,7 +202,7 @@ Spustíte-li čas od času příkaz `git svn rebase`, budete mít jistotu, že p ### Problémy s větvemi systému Git ### -Pokud vám vyhovuje způsob práce v systému Git, začnete pravděpodobně vytvářet tematické větve, budete v nich vytvářet svou práci a začleňovat je. Odesíláte-li revize na server Subversion nástrojem git svn, budete možná chtít pokaždé raději přeskládat svou práci na jedinou větev, místo abyste je slučovali. Důvod, proč raději využít možnosti přeskládání, spočívá v tom, že Subversion má lineární historii a neprovádí začleňování stejně jako Git. Nástroj git svn tak při konverzi snímků na revize Subversion sleduje pouze prvního rodiče. +Jakmile pracovní postupy v systému Git zvládnete, začnete pravděpodobně vytvářet tematické větve, budete v nich pracovat a potom je budete začleňovat (merge). Pokud odesíláte revizi na server Subversion nástrojem `git svn`, budete možná místo slučování chtít svou práci pokaždé přeskládat (rebase) na jedinou větev. Důvod, proč raději využít možnosti přeskládání, spočívá v tom, že Subversion uchovává lineární historii a neprovádí začleňování stejně jako Git. Takže `git svn` při konverzi snímků na revize Subversion sleduje pouze prvního rodiče. Předpokládejme, že vaše historie vypadá následovně: vytvořili jste větev `experiment`, zapsali jste dvě revize a začlenili jste je zpět do větve `master`. Výstup příkazu `dcommit` bude nyní vypadat následovně: @@ -231,7 +231,7 @@ Pokud tuto práci naklonuje jiný uživatel, uvidí jen jednu revizi vzniklou sl ### Větve v systému Subversion ### -Princip větvení v systému Subversion se odlišuje od větvení v systému Git. Pokud se mu můžete úplně vyhnout, mohu vám to vřele doporučit. Pokud se mu vyhnout nelze, můžete i tady použít nástroj git svn, pomocí nějž lze vytvářet nové větve a zapisovat do nich revize. +Princip větvení v systému Subversion se odlišuje od větvení v systému Git. Pravděpodobně nejlepší bude, když se mu pokusíte co nejvíc vyhýbat. Nicméně příkaz `git svn` vytváření větví a zapisování revizí do systému Subversion umožňuje. #### Vytvoření nové větve SVN #### @@ -288,7 +288,7 @@ O příkazu `git svn log` byste měli vědět dvě důležité věci. Zaprvé to #### Anotace SVN #### -Tak jako příkaz `git svn log` simuluje offline příkaz `svn log`, ekvivalentem příkazu `svn annotate` je `git svn blame [SOUBOR]`. Jeho výstup vypadá takto: +Tak jako příkaz `git svn log` simuluje příkaz `svn log` (bez nutnosti připojení), ekvivalentem příkazu `svn annotate` je provedení `git svn blame [SOUBOR]`. Jeho výstup vypadá takto: $ git svn blame README.txt 2 temporal Protocol Buffers - Google's data interchange format @@ -324,6 +324,17 @@ Stejné informace, jaké poskytuje příkaz `svn info`, získáte příkazem `gi Stejně jako v případě příkazů `blame` a `log` pracuje i tento příkaz offline a zobrazuje stav v okamžiku, kdy jste naposledy komunikovali se serverem Subversion. +Tip: Pokud vaše skripty pro sestavení projektu chtějí spouštět `svn info`, pak si často můžete vystačit s obálkou příkazu git. +Můžete vyzkoušet + + #!/usr/bin/env bash + + if git rev-parse --git-dir > /dev/null 2>&1 && [[ $1 == "info" ]] ; then + git svn info + else + /usr/local/bin/svn "$@" + fi + #### Ignorování souborů, které ignoruje Subversion #### Jestliže naklonujete repozitář Subversion s nastavenými vlastnostmi `svn:ignore`, pravděpodobně budete chtít nastavit také odpovídající soubory `.gitignore`, abyste omylem nezapsali nežádoucí soubory. Nástroj `git svn` vám k řešení tohoto problému nabízí dva příkazy. Tím prvním je `git svn create-ignore`, jenž automaticky vytvoří odpovídající soubory `.gitignore`, podle nichž se bude řídit už vaše příští revize. @@ -369,7 +380,7 @@ Vytvoříte tím log ve formátu XML. Můžete v něm vyhledávat autory, vytvo Tento soubor můžete dát k dispozici nástroji `git svn`, aby mohl přesněji zmapovat informace o autorech. Nástroji `git svn` můžete také zadat, aby ignoroval metadata, která systém Subversion normálně importuje: zadejte parametr `--no-metadata` k příkazu `clone` nebo `init`. Váš příkaz `import` pak bude mít tuto podobu: - $ git-svn clone http://my-project.googlecode.com/svn/ \ + $ git svn clone http://my-project.googlecode.com/svn/ \ --authors-file=users.txt --no-metadata -s my_project Import ze systému Subversion v adresáři `my_project` by měl nyní vypadat o něco lépe. Revize už nebudou mít tuto podobu: @@ -392,7 +403,7 @@ they look like this: Nejenže teď pole Author vypadá podstatně lépe, ale navíc jste se zbavili i záznamu `git-svn-id`. -Po importu bude nutné data trochu vyčistit. Zaprvé je nutné vyčistit nejasné reference, které vytvořil příkaz `git svn`. Nejprve přesunete značky tak, aby se z nich staly skutečné značky, a ne podivné vzdálené větve. V dalším kroku přesunete zbytek větví a uděláte z nich větve lokální. +Po importu bude nutné data trochu vyčistit. Zaprvé je nutné vyčistit podivné reference, které vytvořil příkaz `git svn`. Nejprve přesuňte značky tak, aby se z nich staly skutečné značky, a ne podivné vzdálené větve. V dalším kroku přesunete zbytek větví a uděláte z nich větve lokální. Abyste značky upravili na korektní gitové značky, spusťte @@ -499,7 +510,7 @@ Jako rychlou ukázku napíšeme jednoduchý importér. Řekněme, že pracujete Chcete-li importovat adresář Git, budeme se muset podívat na to, jak Git ukládá svá data. Jak si možná vzpomínáte, říkali jsme, že Git je v podstatě seznam odkazů na objekty revizí, které ukazují na určitý snímek obsahu. Jediné, co tedy musíte udělat, je sdělit příkazu `fast-import`, co je obsahem snímků, jaká data revizí na ně ukazují a pořadí, v němž budou převzaty. Vaše strategie tedy bude spočívat v tom, že postupně projdete jednotlivé snímky a vytvoříte revize s obsahem každého adresáře, přičemž každá revize bude odkazovat na revizi předchozí. -Stejně jako v části „Příklad systémem Git kontrolovaných standardů“ v kapitole 7 použijeme i tentokrát Ruby, s nímž většinou pracuji a který je srozumitelný. Tento příklad můžete ale beze všeho napsat v čemkoli, co vám vyhovuje. Jedinou podmínkou je, aby byly potřebné informace zapsány do výstupu stdout. +Stejně jako v podkapitole „Příklad vynucení chování systémem Git“ v kapitole 7 použijeme i tentokrát Ruby, s nímž většinou pracuji a který je srozumitelný. Tento příklad můžete ale beze všeho napsat v čemkoli, co vám vyhovuje. Jedinou podmínkou je, aby byly potřebné informace zapsány na standardní výstup (stdout). A to v případě používání Windows znamená, že budete muset věnovat zvláštní pozornost tomu, abyste na koncích řádků nevkládali znaky CR (carriage return). Příkaz `git fast-import` je v tomto směru velmi vybíravý a chce jen znaky LF (line feed) a nikoliv kombinaci CRLF, kterou používají Windows. Na začátku přejdete do cílového adresáře a identifikujete všechny podadresáře, z nichž bude každý představovat jeden snímek, který chcete importovat jako revizi. Přejdete do každého podadresáře a zadáte příkazy potřebné k jeho exportu. Základní smyčka bude mít tuto podobu: @@ -601,7 +612,7 @@ Poslední věcí, kterou musíte udělat, je vrátit aktuální označovač, aby return mark -Poznámka: Pokud používáte Windows, budete muset provést jeden krok navíc. Jak už jsem se zmínil, Windows používají nahrazují znak konce řádku posloupností CRLF, zatímco git fast-import očekává pouze LF. Abychom tento problém obešli a aby si git fast-import nestěžoval, musíte ruby říct, aby místo LF používal CRLF: +Poznámka: Pokud používáte Windows, budete muset provést jeden krok navíc. Jak už jsem se zmínil, Windows nahrazují znak konce řádku posloupností CRLF, zatímco `git fast-import` očekává pouze LF. Abychom tento problém obešli a přitom učinili příkaz `git fast-import` šťastným, musíte ruby říct, aby místo LF používal CRLF: $stdout.binmode diff --git a/cs/09-git-internals/01-chapter9.markdown b/cs/09-git-internals/01-chapter9.markdown index 81708d2b4..33ac85619 100644 --- a/cs/09-git-internals/01-chapter9.markdown +++ b/cs/09-git-internals/01-chapter9.markdown @@ -27,7 +27,7 @@ Spustíte-li v novém nebo existujícím adresáři příkaz `git init`, Git vyt objects/ refs/ -Možná ve svém adresáři najdete i další soubory. Toto je však příkazem `git init` čerstvě vytvořený repozitář s výchozím obsahem. Adresář `branches` se už v novějších verzích systému Git nepoužívá a soubor `description` používá pouze program GitWeb, o tyto dvě položky se tedy nemusíte starat. Soubor `config` obsahuje jednotlivá nastavení pro konfiguraci vašeho projektu a v adresáři `info` je uchováván globální soubor .gitignore s maskami ignorovaných souborů a adresářů, které si nepřejete sledovat. Adresář `hooks` obsahuje skripty zásuvných modulů na straně klienta nebo serveru, které jsme podrobně popisovali v kapitole 6. +Možná ve svém adresáři najdete i další soubory. Toto je však příkazem `git init` čerstvě vytvořený repozitář s výchozím obsahem. Adresář `branches` se už v novějších verzích systému Git nepoužívá a soubor `description` používá pouze program GitWeb, takže o tyto dvě položky se nemusíte starat. Soubor `config` obsahuje konfigurační nastavení vašeho projektu a v adresáři `info` je uložen globální soubor `exclude` s maskami ignorovaných souborů a adresářů, které chcete explicitně ignorovat prostřednictvím souboru `.gitignore`. Adresář `hooks` obsahuje skripty zásuvných modulů na straně klienta nebo serveru, které jsme podrobně popisovali v kapitole 7. Zbývají čtyři důležité položky: soubory `HEAD` a `index` a adresáře `objects` a `refs`. To jsou ústřední součásti adresáře Git. V adresáři `objects` je uložen celý obsah vaší databáze, v adresáři `refs` jsou uloženy ukazatele na objekty revizí v datech (větve). Soubor `HEAD` ukazuje na větev, na níž se právě nacházíte, a soubor `index` je pro systém Git úložištěm informací o oblasti připravených změn. Na každou z těchto částí se teď podíváme podrobněji, abyste pochopili, jak Git pracuje. @@ -433,7 +433,7 @@ Vraťme se zpět do databáze objektů vašeho testovacího repozitáře Git. V Git komprimuje obsah těchto souborů metodou zlib a uložená data tak nejsou příliš velká. Všechny tyto soubory zabírají dohromady pouhých 925 bytů. Do repozitáře tak nyní přidáme větší objem dat, na němž si budeme moci ukázat jednu zajímavou funkci systému Git. Z knihovny Grit, s níž jsme pracovali před časem, přidejte soubor „repo.rb“. Je to soubor se zdrojovým kódem o velikosti asi 12 kB: - $ curl https://raw.github.com/mojombo/grit/master/lib/grit/repo.rb > repo.rb + $ curl -L https://raw.github.com/mojombo/grit/master/lib/grit/repo.rb > repo.rb $ git add repo.rb $ git commit -m 'added repo.rb' [master 484a592] added repo.rb diff --git a/de/01-introduction/01-chapter1.markdown b/de/01-introduction/01-chapter1.markdown index 3c95fcbb9..28c1e64e3 100644 --- a/de/01-introduction/01-chapter1.markdown +++ b/de/01-introduction/01-chapter1.markdown @@ -54,7 +54,7 @@ Dieser Aufbau hat viele Vorteile gegenüber Lokalen Versionskontrollsystemen. Zu -Allerdings hat dieser Aufbau auch einige erhebliche Nachteile. Der offensichtlichste Nachteil ist der „Single Point of Failure“, den der zentralisierte Server darstellt. Wenn dieser Server für nur eine Stunde nicht verfügbar ist, dann kann in dieser Stunde niemand in irgendeiner Form mit anderen arbeiten oder versionierte Änderungen an den Dateien speichern, an denen sie momentan arbeiten. Wenn die auf dem zentralen Server verwendete Festplatte beschädigt wird und keine Sicherheitskopien erstellt wurden, dann sind all diese Daten unwiederbringlich verloren – die komplette Historie des Projektes, abgesehen natürlich von dem jeweiligen Zustand, den Mitarbeiter gerade zufällig auf ihrem Rechner haben. Lokale Versionskontrollsysteme haben natürlich dasselbe Problem: wenn man die Historie eines Projektes an einer einzigen, zentralen Stelle verwaltet, riskiert man, sie vollständig zu verlieren, wenn irgendetwas an dieser zentralen Stelle ersthaft schief läuft. +Allerdings hat dieser Aufbau auch einige erhebliche Nachteile. Der offensichtlichste Nachteil ist der „Single Point of Failure“, den der zentralisierte Server darstellt. Wenn dieser Server für nur eine Stunde nicht verfügbar ist, dann kann in dieser Stunde niemand in irgendeiner Form mit anderen arbeiten oder versionierte Änderungen an den Dateien speichern, an denen sie momentan arbeiten. Wenn die auf dem zentralen Server verwendete Festplatte beschädigt wird und keine Sicherheitskopien erstellt wurden, dann sind all diese Daten unwiederbringlich verloren – die komplette Historie des Projektes, abgesehen natürlich von dem jeweiligen Zustand, den Mitarbeiter gerade zufällig auf ihrem Rechner haben. Lokale Versionskontrollsysteme haben natürlich dasselbe Problem: wenn man die Historie eines Projektes an einer einzigen, zentralen Stelle verwaltet, riskiert man, sie vollständig zu verlieren, wenn irgendetwas an dieser zentralen Stelle ernsthaft schief läuft. ### Verteilte Versionskontrollsysteme ### @@ -83,11 +83,11 @@ Wie viele großartige Dinge im Leben entstand Git aus kreativem Chaos und hitzig 2005 ging die Beziehung zwischen der Community, die den Linux Kernel entwickelte, und des kommerziell ausgerichteten Unternehmens, das BitKeeper entwickelte, kaputt. Die zuvor ausgesprochene Erlaubnis, BitKeeper kostenlos zu verwenden, wurde widerrufen. Dies war für die Linux Entwickler Community (und besonders für Linus Torvald, der Erfinder von Linux) der Auslöser dafür, ein eigenes Tool zu entwickeln, das auf den Erfahrungen mit BitKeeper basierte. Ziele des neuen Systems waren unter anderem: - + + + + + * Geschwindigkeit * Einfaches Design @@ -206,9 +206,9 @@ Die Staging Area ist einfach eine Datei (normalerweise im Git Verzeichnis), in d Der grundlegend Git Arbeitsprozess sieht in etwa so aus: - + + + 1. Du bearbeitest Dateien in Deinem Arbeitsverzeichnis. 2. Du markierst Dateien für den nächsten Commit, indem Du Snapshots zur Staging Area hinzufügst. @@ -221,7 +221,7 @@ Wenn eine bestimmte Version einer Datei im Git Verzeichnis liegt, gilt sie als ## Git installieren ## - + Lass uns damit anfangen, Git tatsächlich zu verwenden. Der erste Schritt besteht natürlich darin, Git zu installieren und das kann, wie üblich, auf unterschiedliche Weisen geschehen. Die beiden wichtigsten bestehen darin, entweder den Quellcode herunterzuladen und selbst zu kompilieren oder ein fertiges Paket für Dein Betriebssystem zu installieren. @@ -252,8 +252,8 @@ Nachdem Du die genannten Bibliotheken installiert hast, besorge Dir die aktuelle Danach kannst Du dann Git kompilieren und installieren: - $ tar -zxf git-1.6.0.5.tar.gz - $ cd git-1.6.0.5 + $ tar -zxf git-1.7.2.2.tar.gz + $ cd git-1.7.2.2 $ make prefix=/usr/local all $ sudo make prefix=/usr/local install @@ -281,11 +281,11 @@ Auf einem Debian-basierten System wie Ubuntu steht Dir apt-get zur Verfügung: ### Installation unter Mac OS X ### - + -Auf einem Mac kann man Git auf zwei Arten installieren. Der einfachste ist, das grafische Git Installationsprogramm zu verwenden, den man von der Google Code Webseite herunterladen kann (siehe Bild 1-7) +Auf einem Mac kann man Git auf zwei Arten installieren. Der einfachste ist, das grafische Git Installationsprogramm zu verwenden, den man von der SourceForge Webseite herunterladen kann (siehe Bild 1-7) - http://code.google.com/p/git-osx-installer + http://sourceforge.net/projects/git-osx-installer/ @@ -302,6 +302,16 @@ Die andere Möglichkeit ist, Git via MacPorts (http://www.macports.org) zu insta Du brauchst die optionalen Features natürlich nicht mit zu installieren, aber es macht Sinn `+svn` zu verwenden, falls Du jemals Git mit einem Subversion Repository verwenden willst. + + +Alternativ kann man Git auch über Homebrew (`http://brew.sh/`) installieren. Hast Du Homebrew bereits, kannst Du Git einfach über den folgenden Befehl installieren: + + $ brew install git + ### Installation unter Windows ### @@ -330,9 +340,9 @@ Nachdem Du jetzt Git auf Deinem System installiert hast, solltest Du Deine Git K Git umfasst das Werkzeug `git config`, das Dir erlaubt, Konfigurationswerte zu verändern. Auf diese Weise kannst Du anpassen, wie Git aussieht und arbeitet. Diese Werte sind an drei verschiedenen Orten gespeichert: - + + + * Die Datei `/etc/gitconfig` enthält Werte, die für jeden Anwender des Systems und all ihre Projekte gelten. Wenn Du `git config` mit der Option `--system` verwendest, wird diese Datei verwendet. * Die Werte in der Datei `~/.gitconfig` gelten ausschließlich für Dich und all Deine Projekte. Wenn Du `git config` mit der Option `--global` verwendest, wird diese Datei verwendet. @@ -340,7 +350,7 @@ Git umfasst das Werkzeug `git config`, das Dir erlaubt, Konfigurationswerte zu v -Auf Windows Systemen sucht Git nach der `.gitconfig` Datei im `$HOME` Verzeichnis (für die meisten Leute ist das das Verzeichnis `C:\Dokumente und Einstellungen\$USER`). Git sucht außerdem auch nach dem Verzeichnis /etc/gitconfig, aber es sucht relativ demjenigen Verzeichnis, in dem Du Git mit Hilfe des Installers installiert hast. +Auf Windows Systemen sucht Git nach der `.gitconfig` Datei im `$HOME` Verzeichnis (für die meisten Leute ist das das Verzeichnis `C:\Dokumente und Einstellungen\$USER`). Es schaut auch immer nach `/etc/gitconfig`, auch wenn dieses relativ zu dem MSys Wurzelverzeichnis ist, welches das ist, wohin Du Git bei der Installation in Windows installiert hast. ### Deine Identität ### @@ -422,8 +432,8 @@ Beispielsweise erhältst Du die Hilfeseite für den `git config` Befehl so: $ git help config - + + Die „manpage“ Dokumentation ist nützlich, weil Du sie Dir jederzeit anzeigen lassen kannst, auch wenn Du offline bist. Wenn Dir die manpages und dieses Buch nicht ausreichen, kannst Du Deine Fragen auch in den Chaträumen `#git` oder `#github` auf dem Freenode IRC Server (irc.freenode.net) stellen. Diese Räume sind in der Regel sehr gut besucht. Normalerweise findet sich unter den hunderten von Anwendern, die oft sehr viel Erfahrung mit Git haben, irgendjemand, der Deine Fragen gern beantwortet. diff --git a/de/02-git-basics/01-chapter2.markdown b/de/02-git-basics/01-chapter2.markdown index 7f4598236..bb13f3dbd 100644 --- a/de/02-git-basics/01-chapter2.markdown +++ b/de/02-git-basics/01-chapter2.markdown @@ -92,8 +92,8 @@ Bild 2-1. Zyklus der Grundzustände Deiner Dateien Das wichtigste Hilfsmittel, um den Zustand zu überprüfen, in dem sich die Dateien in Deinem Repository gerade befinden, ist der Befehl `git status`. Wenn Du diesen Befehl unmittelbar nach dem Klonen eines Repositorys ausführst, sollte er folgende Ausgabe liefern: $ git status - # On branch master - nothing to commit (working directory clean) + On branch master + nothing to commit, working directory clean @@ -105,16 +105,17 @@ Sagen wir Du fügst eine neue `README` Datei zu Deinem Projekt hinzu. Wenn die D $ vim README $ git status - # On branch master - # Untracked files: - # (use "git add ..." to include in what will be committed) - # - # README + On branch master + Untracked files: + (use "git add ..." to include in what will be committed) + + README + nothing added to commit but untracked files present (use "git add" to track) -Alle Dateien, die in der Sektion „Untracked files“ aufgelistet werden, sind Dateien, die bisher nocht nicht versioniert sind. Dort wird jetzt auch die Datei `README` angezeigt. Mit anderen Worten, die Datei `README` wird in diesem Bereich gelistet, weil sie im letzen Snapshot (Commit) von Git nicht enthalten ist. Git nimmt eine solche Datei nicht automatisch in die Versionskontrolle auf, sondern man muss Git dazu ausdrücklich auffordern. Ansonsten würden generierte Binärdateien oder andere Dateien, die Du nicht in Deinem Repository haben willst, automatisch hinzugefügt werden. Das möchte man in den meisten Fällen vermeiden. Jetzt wollen wir aber Änderungen an der Datei `README` verfolgen und fügen sie deshalb zur Versionskontrolle hinzu. +Alle Dateien, die in der Sektion „Untracked files“ aufgelistet werden, sind Dateien, die bisher noch nicht versioniert sind. Dort wird jetzt auch die Datei `README` angezeigt. Mit anderen Worten, die Datei `README` wird in diesem Bereich gelistet, weil sie im letzen Snapshot (Commit) von Git nicht enthalten ist. Git nimmt eine solche Datei nicht automatisch in die Versionskontrolle auf, sondern man muss Git dazu ausdrücklich auffordern. Ansonsten würden generierte Binärdateien oder andere Dateien, die Du nicht in Deinem Repository haben willst, automatisch hinzugefügt werden. Das möchte man in den meisten Fällen vermeiden. Jetzt wollen wir aber Änderungen an der Datei `README` verfolgen und fügen sie deshalb zur Versionskontrolle hinzu. ### Neue Dateien zur Versionskontrolle hinzufügen ### @@ -130,12 +131,12 @@ Um eine neue Datei zur Versionskontrolle hinzuzufügen, verwendest Du den Befehl Wenn Du den `git status` Befehl erneut ausführst, siehst Du, dass sich Deine `README` Datei jetzt unter Versionskontrolle befindet und für den nächsten Commit vorgemerkt ist (gestaged ist): $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README + @@ -149,17 +150,18 @@ Dass die Datei für den nächsten Commit vorgemerkt ist, siehst Du daran, dass s Wenn Du eine bereits versionierte Datei `benchmarks.rb` änderst und den `git status` Befehl ausführst, erhältst Du folgendes: $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + @@ -167,13 +169,13 @@ Die Datei `benchmarks.rb` erscheint in der Sektion „Changes not staged for com $ git add benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README + modified: benchmarks.rb + @@ -181,18 +183,19 @@ Beide Dateien sind nun für den nächsten Commit vorgemerkt. Nehmen wir an, Du w $ vim benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # modified: benchmarks.rb - # - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README + modified: benchmarks.rb + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + @@ -200,13 +203,13 @@ Huch, was ist das? Jetzt wird `benchmarks.rb` sowohl in der Staging Area als auc $ git add benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README + modified: benchmarks.rb + ### Dateien ignorieren ### @@ -227,10 +230,10 @@ Die erste Zeile weist Git an, alle Dateien zu ignorieren, die mit einem `.o` ode Folgende Regeln gelten in einer `.gitignore` Datei: - + + + + * Leere Zeilen oder Zeilen, die mit `#` beginnen, werden ignoriert. * Standard `glob` Muster funktionieren. @@ -245,6 +248,20 @@ Glob Muster sind vereinfachte reguläre Ausdrücke, die von der Shell verwendet Hier ist ein weiteres Beispiel für eine `.gitignore` Datei: + + + + + + + + + + + + + + # ein Kommentar - dieser wird ignoriert # ignoriert alle Dateien, die mit .a enden *.a @@ -252,12 +269,16 @@ Hier ist ein weiteres Beispiel für eine `.gitignore` Datei: !lib.a # ignoriert eine TODO Datei nur im Wurzelverzeichnis, nicht aber /TODO - # in Unterverzeichnissen - # ignoriert alle Dateien im build/ Verzeichnis build/ # ignoriert doc/notes.txt, aber nicht doc/server/arch.txt doc/*.txt + # ignoriert alle .txt Dateien unterhalb des doc/ Verzeichnis + doc/**/*.txt + + + +Die Kombination `**/` wurde in der Git Version 1.8.2 eingeführt. ### Die Änderungen in der Staging Area durchsehen ### @@ -271,17 +292,18 @@ Wenn Dir die Ausgabe des Befehl `git status` nicht aussagekräftig genug ist, we Nehmen wir an, Du hast die Datei `README` geändert und für einen Commit in der Staging Area vorgemerkt. Dann änderst Du außerdem die Datei `benchmarks.rb`, fügst sie aber noch nicht zur Staging Area hinzu. Wenn Du den `git status` Befehl dann ausführst, zeigt er Dir in etwa Folgendes an: $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + @@ -336,16 +358,18 @@ Ein anderes Beispiel: Wenn Du Änderungen an der Datei `benchmarks.rb` bereits z $ git add benchmarks.rb $ echo '# test line' >> benchmarks.rb $ git status - # On branch master - # - # Changes to be committed: - # - # modified: benchmarks.rb - # - # Changes not staged for commit: - # - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: benchmarks.rb + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + @@ -386,8 +410,8 @@ und `git diff --cached`, um zu sehen, was für den nächsten Commit vorgesehen i ### Einen Commit erzeugen ### - + + Nachdem Du jetzt alle Änderungen, die Du im nächsten Commit haben willst, in Deiner Staging Area gesammelt hast, kannst Du den Commit anlegen. Denke daran, dass Änderungen, die nicht in der Staging Area sind (also alle Änderungen, die Du vorgenommen hast, seit Du zuletzt `git add` ausgeführt hast), auch nicht in den Commit aufgenommen werden. Sie werden ganz einfach weiterhin als geänderte Dateien im Arbeitsverzeichnis verbleiben. In unserem Beispiel haben wir gesehen, dass alle Änderungen vorgemerkt waren, als wir zuletzt `git status` ausgeführt haben, also können wir den Commit jetzt anlegen. Das geht am einfachsten mit dem Befehl: @@ -405,10 +429,9 @@ Der Editor zeigt in etwa folgenden Text an (dies ist ein Beispiel mit vim): # with '#' will be ignored, and an empty message aborts the commit. # On branch master # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # # new file: README # modified: benchmarks.rb + # ~ ~ ~ @@ -423,8 +446,8 @@ Du siehst, dass die vorausgefüllte Commit Meldung die Ausgabe des letzten `git Alternativ kannst Du die Commit Meldung direkt mit dem Befehl `git commit` angeben, indem Du die Option `-m` wie folgt verwendest: $ git commit -m "Story 182: Fix benchmarks for speed" - [master]: created 463dc4f: "Fix benchmarks for speed" - 2 files changed, 3 insertions(+), 0 deletions(-) + [master 463dc4f] Fix benchmarks for speed + 2 files changed, 3 insertions(+) create mode 100644 README @@ -443,15 +466,17 @@ Denke daran, dass jeder neue Commit denjenigen Snapshot aufzeichnet, den Du in d Obwohl die Staging Area unglaublich nützlich ist, um genau diejenigen Commits anzulegen, die Du in Deiner Projekt Historie haben willst, ist sie manchmal auch ein bisschen umständlich. Git stellt Dir deshalb eine Alternative zur Verfügung, mit der Du die Staging Area überspringen kannst. Wenn Du den Befehl `git commit` mit der Option `-a` ausführst, übernimmt Git automatisch alle Änderungen an dejenigen Dateien, die sich bereits unter Versionskontrolle befinden, in den Commit – sodass Du auf diese Weise den Schritt `git add` weglassen kannst: $ git status - # On branch master - # - # Changes not staged for commit: - # - # modified: benchmarks.rb - # + On branch master + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + + no changes added to commit (use "git add" and/or "git commit -a") $ git commit -a -m 'added new benchmarks' [master 83e38c7] added new benchmarks - 1 files changed, 5 insertions(+), 0 deletions(-) + 1 files changed, 5 insertions(+) @@ -470,13 +495,14 @@ Wenn Du einfach nur eine Datei aus dem Arbeitsverzeichnis löschst, wird sie in $ rm grit.gemspec $ git status - # On branch master - # - # Changes not staged for commit: - # (use "git add/rm ..." to update what will be committed) - # - # deleted: grit.gemspec - # + On branch master + Changes not staged for commit: + (use "git add/rm ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + deleted: grit.gemspec + + no changes added to commit (use "git add" and/or "git commit -a") @@ -485,13 +511,12 @@ Wenn Du jetzt `git rm` ausführst, wird diese Änderung für den nächsten Commi $ git rm grit.gemspec rm 'grit.gemspec' $ git status - # On branch master - # - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # deleted: grit.gemspec - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + deleted: grit.gemspec + @@ -538,14 +563,12 @@ Das funktioniert einwandfrei. Wenn Du diesen Befehl ausführst und danach den `g $ git mv README.txt README $ git status - # On branch master - # Your branch is ahead of 'origin/master' by 1 commit. - # - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # renamed: README.txt -> README - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + renamed: README.txt -> README + Allerdings kannst Du genauso folgendes tun: @@ -617,11 +640,13 @@ Eine sehr nützliche Option ist `-p`. Sie zeigt die Änderungen an, die in einem index a874b73..8f94139 100644 --- a/Rakefile +++ b/Rakefile - @@ -5,7 +5,7 @@ require 'rake/gempackagetask' + @@ -5,5 +5,5 @@ require 'rake/gempackagetask' spec = Gem::Specification.new do |s| + s.name = "simplegit" - s.version = "0.1.0" + s.version = "0.1.1" s.author = "Scott Chacon" + s.email = "schacon@gee-mail.com commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 Author: Scott Chacon @@ -644,10 +669,37 @@ Eine sehr nützliche Option ist `-p`. Sie zeigt die Änderungen an, die in einem -end \ No newline at end of file - + + +Diese Option zeigt also im Prinzip die gleiche Information wie zuvor, aber zusätzlich zu jedem Eintrag ein Diff. Das ist nützlich, um einen Code Review zu machen oder eben mal eine Reihe von Commits durchzuschauen, die ein Mitarbeiter angelegt hat. + + + +Manchmal ist es einfacher Änderungen an Hand der Wörter anstatt zeilenbasiert zu überprüfen. Git bietet dafür die Option `--word-diff`, welche man an den Befehl `git log -p` anhängen kann. Man weist Git damit an, einen Vergleich auf Basis der Wörter anstatt Zeile für Zeile durchzuführen. Dieser Vergleich ist ziemlich nutzlos wenn man Änderungen innerhalb von Quellcode vergleicht. Beim Vergleich von langen Textdateien zeigt er aber seine Stärke. Er bietet sich zum Beispiel für Bücher oder wissenschaftliche Texte an. Hierzu ein Beispiel: -Diese Option zeigt also im Prinzip die gleiche Information wie zuvor, aber zusätzlich zu jedem Eintrag ein Diff. Das ist nützlich, um einen Code Review zu machen oder eben mal eine Reihe von Commits durchzuschauen, die ein Mitarbeiter angelegt hat. Außerdem gibt es verschiedene Optionen, die nützlich sind, um Dinge zusammenzufassen. Beispielsweise kannst Du eine kurze Statistik über jeden Commit mit der Option `--stat` anzeigen lassen: + $ git log -U1 --word-diff + commit ca82a6dff817ec66f44342007202690a93763949 + Author: Scott Chacon + Date: Mon Mar 17 21:52:11 2008 -0700 + + changed the version number + + diff --git a/Rakefile b/Rakefile + index a874b73..8f94139 100644 + --- a/Rakefile + +++ b/Rakefile + @@ -7,3 +7,3 @@ spec = Gem::Specification.new do |s| + s.name = "simplegit" + s.version = [-"0.1.0"-]{+"0.1.1"+} + s.author = "Scott Chacon" + + + +Wie man in der Ausgabe sehen kann, zeigt dieser Vergleich nicht an, welche Zeilen hinzugekommen und welche entfallen sind. Stattdessen werden Änderungen innerhalb der Zeilen dargestellt. Mit der Sequenz `{+ +}` wird ein neu hinzugekommes Wort gekennzeichnet, mit `[- -]` ein Wort, welches entfernt wurde. Normalerweise zeigt Git bei einem Vergleich drei zusätzliche Zeilen ober- und unterhalb der eigentlichen Änderung an. Bei einem Textvergleich reicht meist eine zusätzliche Zeile. Man kann dies mit der Option `-U1` erreichen, so wie in dem oben gezeigten Beispiel. + + + +Außerdem gibt es verschiedene Optionen, die nützlich sind, um Dinge zusammenzufassen. Beispielsweise kannst Du eine kurze Statistik über jeden Commit mit der Option `--stat` anzeigen lassen: $ git log --stat commit ca82a6dff817ec66f44342007202690a93763949 @@ -657,7 +709,7 @@ Diese Option zeigt also im Prinzip die gleiche Information wie zuvor, aber zusä changed the version number Rakefile | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) + 1 file changed, 1 insertion(+), 1 deletion(-) commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 Author: Scott Chacon @@ -666,7 +718,7 @@ Diese Option zeigt also im Prinzip die gleiche Information wie zuvor, aber zusä removed unnecessary test code lib/simplegit.rb | 5 ----- - 1 files changed, 0 insertions(+), 5 deletions(-) + 1 file changed, 5 deletions(-) commit a11bef06a3f659402fe7563abf99ad00de2209e6 Author: Scott Chacon @@ -677,10 +729,10 @@ Diese Option zeigt also im Prinzip die gleiche Information wie zuvor, aber zusä README | 6 ++++++ Rakefile | 23 +++++++++++++++++++++++ lib/simplegit.rb | 25 +++++++++++++++++++++++++ - 3 files changed, 54 insertions(+), 0 deletions(-) + 3 files changed, 54 insertions(+) - + + Die `--stat` Option zeigt unterhalb jedes Commits eine kurze Statistik über die jeweiligen Änderungen an: welche Dateien geändert wurden und wieviele Zeilen insgesamt hinzugefügt oder entfernt wurden. Eine weitere nützliche Option ist `--pretty`. Diese Option ändert das Format der Ausgabe und es gibt eine Anzahl mitgelieferter Formate. Das `oneline` Format listet jeden Commit in einer einzigen Zeile, was nützlich ist, wenn Du eine große Anzahl von Commits durchsuchen willst. Die `short`, `full` und `fuller` Formate zeigen die Commits in ähnlicher Form an, aber mit jeweils mehr oder weniger Informationen. @@ -702,22 +754,22 @@ Eines der interessantesten Formate ist `format`, das Dir erlaubt, Dein eigenes F Tabelle 2-1 zeigt einige nützliche Optionen, die von `format` akzeptiert werden: - + + + + + + + + + + + + + + + + Option Beschreibung %H Commit Hash @@ -760,20 +812,22 @@ Die `oneline` und `format` Optionen können außerdem zusammen mit einer weitere Das sind nur einige eher simple Format Optionen für die Ausgabe von `git log` – es gibt sehr viel mehr davon. Tabelle 2-2 listet diejenigen Optionen auf, die wir bisher besprochen haben, und einige weitere, die besonders nützlich sind: - + + + + + + + + + + + + Option Beschreibung -p Zeigt den Patch, der einem Commit entspricht. + --word-diff Führt den Vergleich Wort für Wort, anstatt Zeile für Zeile aus. --stat Zeigt Statistiken über die in einem Commit geänderten Dateien und eingefügten/entfernten Zeilen. --shortstat Zeigt nur die Kurzstatistik über eingefügte/entfernte Zeilen aus der `--stat` Option. --name-only Zeigt die Liste der geänderte Dateien nach der Commit Information. @@ -812,12 +866,12 @@ Eine letzte sehr nützliche Option, die von `git log` akzeptiert wird, ist ein P Tabelle 2-3 zeigt die besprochenen und einige weitere, übliche Optionen: - + + + + + + Option Beschreibung -(n) Begrenzt die Ausgabe auf die letzten n commits @@ -911,33 +965,34 @@ Die nächsten zwei Abschnitte gehen darauf ein, wie Du Änderungen in der Stagin $ git add . $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # modified: README.txt - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: README.txt + modified: benchmarks.rb + Direkt unter der Zeile „Changes to be committed“ findest Du den Hinweis „use `git reset HEAD ...` to unstage“, d.h. „aus der Staging Area zu entfernen“. Wir verwenden nun also diesen Befehl, um die Änderungen an der Datei `benchmarks.rb` aus der Staging Area zu nehmen: $ git reset HEAD benchmarks.rb - benchmarks.rb: locally modified + Unstaged changes after reset: + M benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # modified: README.txt - # - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # (use "git checkout -- ..." to discard changes in working directory) - # - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: README.txt + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + @@ -950,12 +1005,12 @@ Der Befehl liest sich zunächst vielleicht etwas merkwürdig, aber wie Du siehst Was aber, wenn Du die Änderungen an der Datei `benchmarks.rb` überhaupt nicht beibehalten willst? D.h., wenn Du sie in den Zustand zurückversetzen willst, in dem sie sich befand, als Du den letzten Commit angelegt hast (oder das Repository geklont hast). Das ist einfach, und glücklicherweise zeigt der `git status` Befehl ebenfalls bereits einen Hinweis dafür an. Die obige Ausgabe enthält den folgenden Text: - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # (use "git checkout -- ..." to discard changes in working directory) - # - # modified: benchmarks.rb - # + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + @@ -963,12 +1018,12 @@ Das sagt ziemlich klar, was wir zu tun haben um die Änderungen an der Datei zu $ git checkout -- benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # modified: README.txt - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: README.txt + @@ -981,8 +1036,8 @@ Beachte, dass alles was jemals in einem Commit in Git enthalten war, fast immer ## Mit externen Repositorys arbeiten ## - + + Um mit anderen via Git zusammenzuarbeiten, musst Du wissen, wie Du auf externe (engl. „remote“) Repositorys zugreifen kannst. Remote Repositorys sind Versionen Deines Projektes, die im Internet oder irgendwo in einem anderen Netzwerk gespeichert sind. Du kannst mehrere solcher Repositorys haben und Du kannst jedes davon entweder nur lesen oder lesen und schreiben. Mit anderen via Git zusammenzuarbeiten impliziert, solche Repositorys zu verwalten und Daten aus ihnen herunter- oder heraufzuladen, um Deine Arbeit für andere verfügbar zu machen. Um Remote Repositorys zu verwalten, muss man wissen, wie man sie anlegt und wieder entfernt, wenn sie nicht mehr verwendet werden, wie man externe Branches verwalten und nachverfolgen kann, und mehr. In diesem Kapitel werden wir auf diese Aufgaben eingehen. @@ -994,12 +1049,12 @@ Um mit anderen via Git zusammenzuarbeiten, musst Du wissen, wie Du auf externe ( Der `git remote` Befehl zeigt Dir an, welche externen Server Du für Dein Projekt lokal konfiguriert hast, und listet die Kurzbezeichnungen für diese Remote Repository auf. Wenn Du ein Repository geklont hast, solltest Du mindestens `origin` sehen – welches der Standardname ist, den Git für denjenigen Server vergibt, von dem Du geklont hast: $ git clone git://github.com/schacon/ticgit.git - Initialized empty Git repository in /private/tmp/ticgit/.git/ - remote: Counting objects: 595, done. - remote: Compressing objects: 100% (269/269), done. - remote: Total 595 (delta 255), reused 589 (delta 253) - Receiving objects: 100% (595/595), 73.31 KiB | 1 KiB/s, done. - Resolving deltas: 100% (255/255), done. + Cloning into 'ticgit'... + remote: Reusing existing pack: 1857, done. + remote: Total 1857 (delta 0), reused 0 (delta 0) + Receiving objects: 100% (1857/1857), 374.35 KiB | 193.00 KiB/s, done. + Resolving deltas: 100% (772/772), done. + Checking connectivity... done. $ cd ticgit $ git remote origin @@ -1074,7 +1129,7 @@ Dieser Befehl lädt alle Daten aus dem Remote Repository herunter, die noch nich -Wenn Du ein Repository geklont hast, legt der Befehl automatisch einen Verweis auf dieses Repository unter dem Namen `origin` an. D.h. `git fetch origin` lädt alle Neuigkeiten herunter, die in dem Remote Repository von anderen hinzugefügt wurden, seit Du es geklont hast (oder zuletzt `git fetch` ausgeführt hast). Es ist wichtig, zu verstehen, dass der `git fetch` Befehl Daten lediglich in Dein lokales Repository lädt. Er führt sich mit Deinen eigenen Commits in keiner Weise zusammen (mergt) oder modifiziert, woran Du gerade arbeitest. D.h. Du musst die heruntergeladenen Änderungen anschließend selbst manuell mit Deinen eigenen zusammeführen, wenn Du das willst. +Wenn Du ein Repository geklont hast, legt der Befehl automatisch einen Verweis auf dieses Repository unter dem Namen `origin` an. D.h. `git fetch origin` lädt alle Neuigkeiten herunter, die in dem Remote Repository von anderen hinzugefügt wurden, seit Du es geklont hast (oder zuletzt `git fetch` ausgeführt hast). Es ist wichtig, zu verstehen, dass der `git fetch` Befehl Daten lediglich in Dein lokales Repository lädt. Er führt sich mit Deinen eigenen Commits in keiner Weise zusammen (mergt) oder modifiziert, woran Du gerade arbeitest. D.h. Du musst die heruntergeladenen Änderungen anschließend selbst manuell mit Deinen eigenen zusammenführen, wenn Du das willst. @@ -1233,6 +1288,7 @@ Die Option `-m` gibt dabei wiederum die Meldung an, die zum Tag hinzugefügt wir Date: Mon Feb 9 14:45:11 2009 -0800 my version 1.4 + commit 15027957951b64cf874c3557a0f3547bd83b3ff6 Merge: 4a447f7... a6b4c97... Author: Scott Chacon @@ -1363,7 +1419,7 @@ Du kannst Commits jederzeit taggen, auch lange Zeit nachdem sie angelegt wurden. Nehmen wir an, dass Du vergessen hast, Version v1.2 des Projekts zu taggen und dass dies der Commit „updated rakefile“ gewesen ist. Du kannst diesen jetzt im Nachhinein taggen, indem Du die Checksumme des Commits (oder einen Teil davon) am Ende des Befehls angibst: - $ git tag -a v1.2 9fceb02 + $ git tag -a v1.2 -m 'version 1.2' 9fceb02 @@ -1435,11 +1491,11 @@ Bevor wir zum Ende dieses Grundlagenkapitels kommen, möchten wir noch einige Ti ### Auto-Vervollständigung ### - + -Wenn Du die Bash Shell verwendest, dann kannst Du ein Skript für die Git Auto-Vervollständigung einbinden. Ein solches Skript wird mit Git zusammen ausgeliefert. Wenn Du den Git Quellcode heruntergeladen hast, findest Du im Verzeichnis `contrib/completion` die Datei `git-completion.bash`. Kopiere diese Datei in Dein Home Verzeichnis und füge die folgende Zeile in Deine `.bashrc` Datei hinzu: +Wenn Du die Bash Shell verwendest, dann kannst Du ein Skript für die Git Auto-Vervollständigung einbinden. Du kannst dieses Skript direkt aus den Git Quellen von https://github.com/git/git/blob/master/contrib/completion/git-completion.bash herunterladen. Kopiere diese Datei in Dein Home Verzeichnis und füge die folgende Zeile in Deine `.bashrc` Datei hinzu: - source ~/.git-completion.bash + source ~/git-completion.bash diff --git a/de/03-git-branching/01-chapter3.markdown b/de/03-git-branching/01-chapter3.markdown index c45229239..6ff4380eb 100644 --- a/de/03-git-branching/01-chapter3.markdown +++ b/de/03-git-branching/01-chapter3.markdown @@ -3,18 +3,18 @@ -Nahezu jedes VCS unterstützt eine Form von Branching. Branching bedeutet, dass Du von der Hauptentwicklungslinie abzweigst und unabhängig von dem Hauptzweig weiterarbeitest. Bei vielen VCS ist das ein umständlicher und komplizierter Prozess. Nicht selten ist es notwendig, dass eine Kopie des kompletten Arbeitsverzeichnisses erstellt werden muss, was bei großen Projekten eine ganze Weile dauern kann. +Nahezu jedes VCS unterstützt eine Form von Branching. Branching bedeutet, dass Du von der Hauptentwicklungslinie abzweigst und unabhängig vom Hauptzweig weiterarbeitest. Bei vielen VCS ist das ein ziemlch aufwendiger Prozess, welcher häufig erfordert, eine Kopie des kompletten Arbeitsverzeichnisses zu erstellen, was bei großen Projekten eine ganze Weile dauern kann. -Manche Leute bezeichnen Gits Branching-Modell als dessen „Killer-Feature“, was Git zweifellos von dem Rest der VCS-Community abhebt. Aber was macht es so besonders? Die Art und Weise, wie Git Branches behandelt, ist unglaublich leichtfüßig. Dies führt dazu, dass nahezu jede Branch-Operation verzögerungsfrei ausgeführt wird. Auch das Hin- und Herschalten zwischen einzelnen Entwicklungszweigen läuft genauso schnell ab. Im Gegensatz zu anderen VCS ermutigt Git zu einer Arbeitsweise mit häufigem Branching und Merging – oft mehrmals am Tag. Die Branching-Funktion zu verstehen und zu meistern gibt Dir ein mächtiges und einmaliges Werkzeug an die Hand und kann Deine Art zu entwickeln buchstäblich verändern. +Manche Leute bezeichnen Gits Branching-Modell als dessen „Killer-Feature“, was Git zweifellos von dem Rest der VCS-Community abhebt. Was ist das Besondere daran? Die Art und Weise, wie Git Branches behandelt, ist unglaublich leichtgewichtig, wodurch Branch-Operationen nahezu verzögerungsfrei ausgeführt werden und auch das Hin- und Herschalten zwischen einzelnen Entwicklungszweigen im allgemeinen genauso schnell abläuft. Im Gegensatz zu anderen VCS ermutigt Git zu einer Arbeitsweise mit häufigem Branching und Merging – oft mehrmals am Tag. Wenn Du diese Funktion vertstehst und beherrschst, besitzt Du ein mächtiges und einmaliges Werkzeug, welches Deine Art zu entwickeln buchstäblich verändern. ## Was ist ein Branch? ## -Um wirklich zu verstehen wie Git Branching durchführt, müssen wir einen Schritt zurück gehen und untersuchen wie Git die Daten speichert. Wie Du Dich vielleicht noch an Kapitel 1 erinnerst, speichert Git seine Daten nicht als Serie von Änderungen oder Unterschieden, sondern als Serie von Schnappschüssen. +Um wirklich zu verstehen, wie Git Branching durchführt, müssen wir einen Schritt zurück gehen und untersuchen, wie Git die Daten speichert. Wie Du Dich vielleicht noch an Kapitel 1 erinnerst, speichert Git seine Daten nicht als Serie von Änderungen oder Unterschieden, sondern als Serie von Schnappschüssen. @@ -24,17 +24,16 @@ Wenn Du in Git committest, speichert Git ein sogenanntes Commit-Objekt. Dieses e Um das zu verdeutlichen, lass uns annehmen, Du hast ein Verzeichnis mit drei Dateien, die Du alle zu der Staging-Area hinzufügst und in einem Commit verpackst. Durch das Stagen der Dateien erzeugt Git für jede Datei eine Prüfsumme (der SHA-1 Hash, den wir in Kapitel 1 erwähnt haben), speichert diese Version der Datei im Git-Repository (Git referenziert auf diese als Blobs) und fügt die Prüfsumme der Staging-Area hinzu: - $ git add README test.rb LICENSE2 + $ git add README test.rb LICENSE $ git commit -m 'initial commit of my project' - + -Wenn Du einen Commit mit dem Kommando `git commit` erstellst, erzeugt Git für jedes Unterverzeichnis eine Prüfsumme (in diesem Fall nur für das Root-Verzeichnis) und speichert diese drei Objekte im Git Repository. Git erzeugt dann ein Commit Objekt, das die Metadaten und den Zeiger zur Wurzel des Projektbaums enthält, um bei Bedarf den Snapshot erneut erzeugen zu können. +Wenn Du einen Commit mit der Anweisung `git commit` erstellst, erzeugt Git für jedes Projektverzeichnis eine Prüfsumme und speichert diese als sogenanntes `tree`-Objekt im Git Repository. Git erzeugt dann ein Commit Objekt, das die Metadaten und den Zeiger zum `tree`-Objekt des Wurzelverzeichnis enthält, um bei Bedarf den Snapshot erneut erzeugen zu können. -Dein Git-Repository enthält nun fünf Objekte: einen Blob für den Inhalt jeder der drei Dateien, einen Baum, der den Inhalt des Verzeichnisses auflistet und spezifiziert welcher Dateiname zu welchem Blob gehört, sowie einen Zeiger, der auf die Wurzel des Projektbaumes und die Metadaten des Commits verweist. Prinzipiell sehen Deine Daten im Git Repository wie in Abbildung 3-1 aus. +Dein Git-Repository enthält nun fünf Objekte: einen Blob für den Inhalt von jeder der drei Dateien, einen Baum, der den Inhalt des Verzeichnisses auflistet und spezifiziert, welcher Dateiname zu welchem Blob gehört, sowie einen Zeiger, der auf die Wurzel des Projektbaumes und die Metadaten des Commits verweist. Prinzipiell sehen Deine Daten im Git Repository wie in Abbildung 3-1 aus. @@ -61,7 +60,7 @@ Abbildung 3-3. Branch, der auf einen Commit in der Historie zeigt. -Was passiert, wenn Du einen neuen Branch erstellst? Nun, zunächst wird ein neuer Zeiger erstellt. Sagen wir, Du erstellst einen neuen Branch mit dem Namen `testing`. Das machst Du mit dem `git branch` Befehl: +Was passiert, wenn Du einen neuen Branch erstellst? Nun, zunächst wird ein neuer Zeiger erstellt. Sagen wir, Du erstellst einen neuen Branch mit dem Namen `testing`. Das machst Du mit der Anweisung `git branch`: $ git branch testing @@ -76,7 +75,7 @@ Abbildung 3-4. Mehrere Branches zeigen in den Commit-Verlauf -Woher weiß Git, welchen Branch Du momentan verwendest? Dafür gibt es einen speziellen Zeiger mit dem Namen HEAD. Berücksichtige, dass dieses Konzept sich grundsätzlich von anderen HEAD-Konzepten anderer VCS, wie Subversion oder CVS, unterscheidet. Bei Git handelt es sich bei HEAD um einen Zeiger, der auf Deinen aktuellen lokalen Branch zeigt. In dem Fall bist Du aber immer noch auf dem `master`-Branch. Das `git branch` Kommando hat nur einen neuen Branch erstellt, aber nicht zu diesem gewechselt (siehe Abbildung 3-5). +Woher weiß Git, welchen Branch Du momentan verwendest? Dafür gibt es einen speziellen Zeiger mit dem Namen HEAD. Berücksichtige, dass dieses Konzept sich grundsätzlich von anderen HEAD-Konzepten anderer VCS, wie Subversion oder CVS, unterscheidet. Bei Git handelt es sich bei HEAD um einen Zeiger, der auf Deinen aktuellen lokalen Branch zeigt. In dem Fall bist Du aber immer noch auf dem `master`-Branch. Die Anweisung `git branch` hat nur einen neuen Branch erstellt, aber nicht zu diesem gewechselt (siehe Abbildung 3-5). @@ -85,7 +84,7 @@ Abbildung 3-5. Der HEAD-Zeiger verweist auf Deinen aktuellen Branch. -Um zu einem anderen Branch zu wechseln, benutze das Kommando `git checkout`. Lass uns nun zu unserem neuen Branch `testing` wechseln: +Um zu einem anderen Branch zu wechseln, benutze die Anweisung `git checkout`. Lass uns nun zu unserem neuen Branch `testing` wechseln: $ git checkout testing @@ -116,7 +115,7 @@ Abbildung 3-7. Der HEAD-Zeiger schreitet mit jedem weiteren Commit voran. -Das ist interessant, denn Dein Branch `testing` hat sich jetzt voranbewegt und Dein `master`-Branch zeigt immer noch auf seinen letzten Commit. Den Commit, den Du zuletzt bearbeitet hattest, bevor Du mit `git checkout` den aktuellen Zweig gewechselt hast. Lass uns zurück zu dem `master`-Branch wechseln: +Das ist interessant, denn Dein Branch `testing` hat sich jetzt voranbewegt, während Dein `master`-Branch immer noch auf den Commit zeigt, welchen Du bearbeitet hast, bevor Du mit `git checkout` den aktuellen Zweig gewechselt hast. Lass uns zurück zu dem `master`-Branch wechseln: $ git checkout master @@ -131,7 +130,7 @@ Abbildung 3-8. HEAD zeigt nach einem Checkout auf einen anderen Branch. -Das Kommando hat zwei Dinge veranlasst. Zum einen bewegt es den HEAD-Zeiger zurück zum `master`-Branch, zum anderen setzt es alle Dateien im Arbeitsverzeichnis auf den Bearbeitungsstand des letzte Commits in diesem Zweig zurück. Das bedeutet aber auch, dass nun alle Änderungen am Projekt vollkommen unabhängig von älteren Projektversionen erfolgen. Kurz gesagt, werden alle Änderungen aus dem `testing`-Zweig vorübergehend rückgängig gemacht und Du hast die Möglichkeit einen vollkommen neuen Weg in der Entwicklung einzuschlagen. +Diese Anweisung hat zwei Dinge veranlasst. Zum einen bewegt es den HEAD-Zeiger zurück zum `master`-Branch, zum anderen setzt es alle Dateien im Arbeitsverzeichnis auf den Bearbeitungsstand des letzten Commits in diesem Zweig zurück. Das bedeutet aber auch, dass nun alle Änderungen am Projekt vollkommen unabhängig von älteren Projektversionen erfolgen. Kurz gesagt, werden alle Änderungen aus dem `testing`-Zweig vorübergehend rückgängig gemacht und Du hast die Möglichkeit, einen vollkommen neuen Weg in der Entwicklung einzuschlagen. @@ -140,10 +139,9 @@ Lass uns ein paar Änderungen machen und mit einem Commit festhalten: $ vim test.rb $ git commit -a -m 'made other changes' - + -Nun verzweigen sich die Projektverläufe (siehe Abbildung 3-9). Du hast einen Branch erstellt und zu ihm gewechselt, hast ein bisschen gearbeitet, bist zu Deinem Haupt-Zweig zurückgekehrt und hast da was ganz anderes gemacht. Beide Arbeiten existieren vollständig unabhängig voneinander in zwei unterschiedlichen Branches. Du kannst beliebig zwischen den beiden Zweigen wechseln und sie zusammenführen, wenn Du meinst es wäre soweit. Und das alles hast Du mit simplen `branch` und `checkout`-Befehlen vollbracht. +Nun verzweigen sich die Projektverläufe (siehe Abbildung 3-9). Du hast einen Branch erstellt und zu ihm gewechselt, hast ein bisschen gearbeitet, bist zu Deinem Haupt-Zweig zurückgekehrt und hast da was ganz anderes gemacht. Beide Arbeiten existieren vollständig unabhängig voneinander in zwei unterschiedlichen Branches. Du kannst beliebig zwischen den beiden Zweigen wechseln und sie zusammenführen, wenn Du meinst, es wäre soweit. Und das alles hast Du mit simplen `branch` und `checkout`-Anweisungen vollbracht. @@ -152,7 +150,7 @@ Abbildung 3-9. Die Historie läuft auseinander. -Branches können in Git spielend erstellt und entfernt werden, da sie nur kleine Dateien sind, die eine 40 Zeichen lange SHA-1 Prüfsumme der Commits enthalten, auf die sie verweisen. Einen neuen Zweig zu erstellen erzeugt ebenso viel Aufwand wie das Schreiben einer 41 Byte großen Datei (40 Zeichen und einen Zeilenumbruch). +Branches können in Git spielend erstellt und entfernt werden, da sie nur kleine Dateien sind, die eine 40 Zeichen lange SHA-1 Prüfsumme der Commits enthalten, auf die sie verweisen. Einen neuen Zweig zu erstellen, erzeugt ebenso viel Aufwand wie das Schreiben einer 41 Byte großen Datei (40 Zeichen und einen Zeilenumbruch). @@ -169,25 +167,25 @@ Lass uns mal sehen, warum Du das machen solltest. Lass uns das Ganze an einem Beispiel durchgehen, dessen Workflow zum Thema Branching und Zusammenführen Du im echten Leben verwenden kannst. Folge einfach diesen Schritten: - + + + 1. Arbeite an einer Webseite. -2. Erstell einen Branch für irgendeine neue Geschichte, an der Du arbeitest. +2. Erstelle einen Branch für irgendeine neue Geschichte, an der Du arbeitest. 3. Arbeite in dem Branch. In diesem Augenblick kommt ein Anruf, dass ein kritisches Problem aufgetreten ist und sofort gelöst werden muss. Du machst folgendes: - + + + + -1. Geh zurück zu Deinem „Produktiv“-Zweig. -2. Erstelle eine Branch für den Hotfix. +1. Schalte zurück zu Deinem „Produktiv“-Zweig. +2. Erstelle einen Branch für den Hotfix. 3. Nach dem Testen führst Du den Hotfix-Branch mit dem „Produktiv“-Branch zusammen. 4. Schalte wieder auf Deine alte Arbeit zurück und werkel weiter. @@ -205,10 +203,10 @@ Abbildung 3-10. Eine kurze, einfache Commit-Historie -Du hast Dich dafür entschieden an dem Issue #53, des Issue-Trackers XY, zu arbeiten. Um eines klarzustellen, Git ist an kein Issue-Tracking-System gebunden. Da der Issue #53 allerdings ein Schwerpunktthema betrifft, wirst Du einen neuen Branch erstellen um daran zu arbeiten. Um in einem Arbeitsschritt einen neuen Branch zu erstellen und zu aktivieren kannst Du das Kommando `git checkout` mit der Option `-b` verwenden: +Du hast Dich dafür entschieden, am Issue #53 des Issue-Trackers XY zu arbeiten. Um eines klarzustellen, Git ist an kein Issue-Tracking-System gebunden. Da der Issue #53 allerdings ein Schwerpunktthema betrifft, wirst Du einen neuen Branch erstellen, um daran zu arbeiten. Um in einem Arbeitsschritt einen neuen Branch zu erstellen und zu aktivieren, kannst Du die Anweisung `git checkout` mit der Option `-b` verwenden: $ git checkout -b iss53 - Switched to a new branch "iss53" + Switched to a new branch 'iss53' @@ -240,49 +238,49 @@ Abbildung 3-12. Der `iss53`-Branch hat mit Deiner Arbeit Schritt gehalten. -Nun bekommst Du einen Anruf, in dem Dir mitgeteilt wird, dass es ein Problem mit der Internet-Seite gibt, das Du umgehend beheben sollst. Mit Git musst Du Deine Fehlerkorrektur nicht zusammen mit den `iss53`-Änderungen einbringen. Und Du musst keine Zeit damit verschwenden Deine bisherigen Änderungen rückgängig zu machen, bevor Du mit der Fehlerbehebung an der Produktionsumgebung beginnen kannst. Alles was Du tun musst, ist zu Deinem MASTER-Branch wechseln. +Nun bekommst Du einen Anruf, in dem Dir mitgeteilt wird, dass es ein Problem mit der Internet-Seite gibt, das Du umgehend beheben sollst. Bei Git musst Du Deine Fehlerkorrektur nicht zusammen mit den `iss53`-Änderungen einbringen. Und Du musst keine Zeit damit verschwenden, Deine bisherigen Änderungen rückgängig zu machen, bevor Du mit der Fehlerbehebung an der Produktionsumgebung beginnen kannst. Alles, was Du tun musst, ist, zu Deinem master-Branch wechseln. -Beachte jedoch, dass Dich Git den Branch nur wechseln lässt, wenn bisherige Änderungen in Deinem Arbeitsverzeichnis oder Deiner Staging-Area nicht in Konflikt mit dem Zweig stehen, zu dem Du nun wechseln möchtest. Am besten es liegt ein sauberer Status vor wenn man den Branch wechselt. Wir werden uns später mit Wegen befassen, dieses Verhalten zu umgehen (namentlich „Stashing“ und „Commit Ammending“). Vorerst aber hast Du Deine Änderungen bereits comitted, sodass Du zu Deinem MASTER-Branch zurückwechseln kannst. +Beachte jedoch, dass Dich Git den Branch nur wechseln lässt, wenn bisherige Änderungen in Deinem Arbeitsverzeichnis oder Deiner Staging-Area nicht in Konflikt mit dem Zweig stehen, zu dem Du nun wechseln möchtest. Am besten ist es, wenn ein sauberer Arbeitsstand vorliegt, wenn man den Branch wechselt. Wir werden uns später mit Wegen befassen, dieses Verhalten zu umgehen (namentlich „Stashing“ und „Commit Ammending“). Vorerst aber hast Du Deine Änderungen bereits comitted, sodass Du zu Deinem master-Branch zurückwechseln kannst. $ git checkout master - Switched to branch "master" + Switched to branch 'master' -Zu diesem Zeitpunkt befindet sich das Arbeitsverzeichnis des Projektes in exakt dem gleichen Zustand, in dem es sich befand, als Du mit der Arbeit an Issue #53 begonnen hast und Du kannst Dich direkt auf Deinen Hotfix konzentrieren. Dies ist ein wichtiger Moment um sich vor Augen zu halten, dass Git Dein Arbeitsverzeichnis auf den Zustand des Commits, auf den dieser Branch zeigt, zurücksetzt. Es erstellt, entfernt und verändert Dateien automatisch, um sicherzustellen, dass Deine Arbeitskopie haargenau so aussieht wie der Zweig nach Deinem letzten Commit. +Zu diesem Zeitpunkt befindet sich das Arbeitsverzeichnis des Projektes in exakt dem gleichen Zustand, in dem es sich befand, als Du mit der Arbeit an Issue #53 begonnen hast und Du kannst Dich direkt auf Deinen Hotfix konzentrieren. Dies ist ein wichtiger Moment, um sich vor Augen zu halten, dass Git Dein Arbeitsverzeichnis auf den Zustand des Commits, auf den dieser Branch zeigt, zurücksetzt. Es erstellt, entfernt und verändert Dateien automatisch, um sicherzustellen, dass Deine Arbeitskopie haargenau so aussieht wie der Zweig nach Deinem letzten Commit. -Nun hast Du einen Hotfix zu erstellen. Lass uns dazu einen Hotfix-Branch erstellen, an dem Du bis zu dessen Fertigstellung arbeitest (siehe Abbildung 3-13): +Nun hast Du einen Hotfix zu erstellen. Lass uns dazu einen hotfix-Branch erstellen, an dem Du bis zu dessen Fertigstellung arbeitest (siehe Abbildung 3-13): - $ git checkout -b 'hotfix' - Switched to a new branch "hotfix" + $ git checkout -b hotfix + Switched to a new branch 'hotfix' $ vim index.html $ git commit -a -m 'fixed the broken email address' - [hotfix]: created 3a0874c: "fixed the broken email address" - 1 files changed, 0 insertions(+), 1 deletions(-) + [hotfix 3a0874c] fixed the broken email address + 1 files changed, 1 deletion(-) Insert 18333fig0313.png -Abbildung 3-13. Der Hotfix-Branch basiert auf dem zurückliegenden Master-Branch. +Abbildung 3-13. Der hotfix-Branch basiert auf dem zurückliegenden master-Branch. -Mach Deine Tests, stell sicher das sich der Hotfix verhält wie erwartet und führe ihn mit dem Master-Branch zusammen, um ihn in die Produktionsumgebung zu integrieren. Das machst Du mit dem `git merge`-Kommando: +Du kannst Deine Tests durchführen und sicherstellen, dass der Hotfix seinen Zweck erfüllt und ihn dann mit dem master-Branch zusammenführen, um ihn in die Produktionsumgebung zu integrieren. Das machst Du mit der Anweisung `git merge`: $ git checkout master $ git merge hotfix Updating f42c576..3a0874c - Fast forward - README | 1 - - 1 files changed, 0 insertions(+), 1 deletions(-) + Fast-forward + README | 1 - + 1 file changed, 1 deletion(-) -Du wirst die Mitteilung „Fast Forward“ während des Zusammenführens bemerken. Da der neue Commit direkt von dem ursprünglichen Commit, auf den sich der nun eingebrachte Zweig bezieht, abstammt, bewegt Git einfach den Zeiger weiter. Mit anderen Worten kann Git den neuen Commit, durch verfolgen der Commitabfolge, direkt erreichen, dann bewegt es ausschließlich den Branch-Zeiger. Zu einer tatsächlichen Kombination der Commits besteht ja kein Anlass. Dieses Vorgehen wird „Fast Forward“ genannt. +Du wirst die Mitteilung „Fast Forward“ während des Zusammenführens bemerken. Da der neue Commit direkt von dem ursprünglichen Commit, auf den sich der nun eingebrachte Zweig bezieht, abstammt, bewegt Git einfach den Zeiger weiter. Mit anderen Worten kann Git den neuen Commit durch Verfolgen der Commitabfolge direkt erreichen, dann bewegt es ausschließlich den Branch-Zeiger. Zu einer tatsächlichen Kombination der Commits besteht ja kein Anlass. Dieses Vorgehen wird „Fast Forward“ genannt. @@ -291,25 +289,25 @@ Deine Modifikationen befinden sich nun als Schnappschuss in dem Commit, auf den Insert 18333fig0314.png -Abbildung 3-14. Der Master-Branch zeigt nach der Zusammenführung auf den gleichen Commit wie der Hotfix-Branch. +Abbildung 3-14. Der master-Branch zeigt nach der Zusammenführung auf den gleichen Commit wie der hotfix-Branch. -Nachdem Dein superwichtiger Hotfix veröffentlicht wurde, kannst Du Dich wieder Deiner ursprünglichen Arbeit zuwenden. Vorher wird sich allerdings des nun nutzlosen Hotfix-Zweiges entledigt, schließlich zeigt der Master-Branch ebenfalls auf die aktuelle Version. Du kannst ihn mit der `-d`-Option von `git branch` entfernen: +Nachdem Dein superwichtiger Hotfix veröffentlicht wurde, kannst Du Dich wieder Deiner ursprünglichen Arbeit zuwenden. Vorher wird sich allerdings des nun nutzlosen hotfix-Zweiges entledigt, schließlich zeigt der master-Branch ebenfalls auf die aktuelle Version. Du kannst ihn mit der `-d`-Option von `git branch` entfernen: $ git branch -d hotfix - Deleted branch hotfix (3a0874c). + Deleted branch hotfix (was 3a0874c). Nun kannst Du zu Deinem Issue #53-Branch zurückwechseln und mit Deiner Arbeit fortfahren (Abbildung 3-15): $ git checkout iss53 - Switched to branch "iss53" + Switched to branch 'iss53' $ vim index.html $ git commit -a -m 'finished the new footer [issue 53]' - [iss53]: created ad82d7a: "finished the new footer [issue 53]" - 1 files changed, 1 insertions(+), 0 deletions(-) + [iss53 ad82d7a] finished the new footer [issue 53] + 1 file changed, 1 insertion(+) @@ -318,7 +316,7 @@ Abbildung 3-15. Dein `iss53`-Branch kann sich unabhängig weiterentwickeln. -An dieser Stelle ist anzumerken, dass die Änderungen an dem `hotfix`-Branch nicht in Deinen `iss53`-Zweig eingeflossen sind. Falls nötig kannst Du den `master`-Branch allerdings mit dem Kommando `git merge master` mit Deinem Zweig kombinieren. Oder Du wartest, bis Du den `iss53`-Branch später in den Master-Zweig zurückführst. +An dieser Stelle ist anzumerken, dass die Änderungen an dem `hotfix`-Branch nicht in Deinen `iss53`-Branch eingeflossen sind. Falls nötig, kannst Du den `master`-Branch allerdings mit der Anweisung `git merge master` mit Deinem Branch kombinieren. Oder Du wartest, bis Du den `iss53`-Branch später in den `master`-Branch zurückführst. @@ -326,30 +324,31 @@ An dieser Stelle ist anzumerken, dass die Änderungen an dem `hotfix`-Branch nic -Angenommen Du entscheidest dich, dass Deine Arbeit an issue #53 getan ist und Du diese mit der `master` Branch zusammenführen möchtest. Das passiert, indem Du ein `merge` in die `iss53` Branch machst, ähnlich dem `merge` mit der `hotfix` Branch von vorhin. Alles was Du machen musst, ist ein `checkout` der Branch, in die Du das `merge` machen willst und das Ausführen des Kommandos `git merge`: +Angenommen, Du hast entschieden, dass Deine Arbeiten an issue #53 abgeschlossen sind und das Ganze soweit ist, dass es mit dem `master` Branch zusammengeführt werden kann. Um das zu erreichen, wirst Du Deinen `iss53` Branch in den `master` Branch einfließen lassen, genauso wie Du es mit dem `hotfix` Branch zuvor getan hast. Du musst nur mit der Anweisung `checkout` zum dem Branch zu wechseln, in welchen Du etwas einfließen lassen möchtest und dann die Anweisung `git merge` ausführen: $ git checkout master $ git merge iss53 - Merge made by recursive. - README | 1 + - 1 files changed, 1 insertions(+), 0 deletions(-) + Auto-merging README + Merge made by the 'recursive' strategy. + README | 1 + + 1 file changed, 1 insertion(+) -Das sieht ein bisschen anders aus als das `hotfix merge` von vorhin. Hier läuft Deine Entwicklungshistorie auseinander. Ein `commit` auf Deine Arbeits-Branch ist kein direkter Nachfolger der Branch in die Du das `merge` gemacht hast, Git hat da einiges zu tun, es macht einen 3-Wege `merge`: es geht von den beiden `snapshots` der Branches und dem allgemeinen Nachfolger der beiden aus. Abbildung 3-16 zeigt die drei `snapshots`, die Git in diesem Fall für das `merge` verwendet. +Das sieht ein bisschen anders aus als das `hotfix merge` von vorhin. Hier haben sich die Entwicklungsstränge schon zu einem früheren Zeitpunkt geteilt. Da der `commit` auf dem Branch, in dem Du Dich befindest, kein direkter Nachfolger von dem Branch ist, in den Du das `merge` machst, hat Git einiges zu tun. Dazu macht Git einen 3-Wege `merge`, wobei es die beiden Schnappschüsse verwendet, welche auf die Enden der Branches zeigen, und den gemeinsamen Vorfahren dieser beiden. Abbildung 3-16 zeigt die drei `snapshots`, die Git in diesem Fall für das `merge` verwendet. Insert 18333fig0316.png -Abbildung 3-16. Git ermittelt automatisch die beste Nachfolgebasis für die Branchzusammenführung. +Abbildung 3-16. Git erkennt automatisch den am besten geeigneten gemeinsamen Vorgänger für die Branchzusammenführung. -Anstatt einfach den 'pointer' weiterzubewegen, erstellt Git einen neuen `snapshot`, der aus dem 3-Wege 'merge' resultiert und erzeugt einen neuen 'commit', der darauf verweist (siehe Abbildung 3-17). Dies wird auch als 'merge commit' bezeichnet und ist ein Spezialfall, weil es mehr als nur ein Elternteil hat. +Anstatt einfach den Zeiger vorwärts zu bewegen, erstellt Git einen neuen `snapshot`, der aus dem 3-Wege 'merge' resultiert und erzeugt automatisch einen neuen `commit`, der darauf verweist (siehe Abbildung 3-17). Dies wird auch als `merge commit` bezeichnet und ist ein Spezialfall, weil es mehr als nur einen Elternteil hat. -Es ist wichtig herauszustellen, dass Git den besten Nachfolger für die 'merge' Basis ermittelt, denn hierin unterscheidet es sich von CVS und Subversion (vor Version 1.5), wo der Entwickler die 'merge' Basis selbst ermitteln muss. Damit wird das Zusammenführen in Git um einiges leichter, als in anderen Systemen. +Es ist wichtig herauszustellen, dass Git den am besten geeigneten gemeinsamen Vorgänger als Grundlage für das Zusammenführen bestimmt, denn hierin unterscheidet es sich von CVS und Subversion (vor Version 1.5), wo der Entwickler beim Zusammenführen die 'merge' Basis selbst ermitteln muss. In Git ist das Zusammenführen dadurch wesentlich einfacher, als in anderen Systemen. @@ -358,7 +357,7 @@ Abbildung 3-17. Git erstellt automatisch ein 'commit', dass die zusammengeführt -Jetzt da wir die Arbeit zusammengeführt haben, ist der `iss53`-Branch nicht mehr notwendig. Du kannst ihn löschen und das Ticket im Ticket-Tracking-System schliessen. +Jetzt, da wir die Arbeit zusammengeführt haben, ist der `iss53`-Branch nicht mehr notwendig. Du kannst ihn löschen und das Ticket im Ticket-Tracking-System schließen. $ git branch -d iss53 @@ -378,54 +377,61 @@ Gelegentlich verläuft der Prozess nicht ganz so glatt. Wenn Du an den selben St Git hat hier keinen 'merge commit' erstellt. Es hat den Prozess gestoppt, damit Du den Konflikt beseitigen kannst. Wenn Du sehen willst, welche Dateien 'unmerged' aufgrund eines 'merge' Konflikts sind, benutze einfach `git status`: - [master*]$ git status - index.html: needs merge - # On branch master - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # (use "git checkout -- ..." to discard changes in working directory) - # - # unmerged: index.html - # + $ git status + On branch master + You have unmerged paths. + (fix conflicts and run "git commit") + + Unmerged paths: + (use "git add ..." to mark resolution) + + both modified: index.html + + no changes added to commit (use "git add" and/or "git commit -a") Alles, was einen 'merge' Konflikt aufweist und nicht gelöst werden konnte, wird als 'unmerged' aufgeführt. Git fügt den betroffenen Dateien Standard-Konfliktlösungsmarker hinzu, sodass Du diese öffnen und den Konflikt manuell lösen kannst. Deine Datei enthält einen Bereich, der so aussehen könnte: - <<<<<<< HEAD:index.html + <<<<<<< HEAD ======= - >>>>>>> iss53:index.html + >>>>>>> iss53 -Das heisst, die Version in HEAD (Deines 'master'-Branches, denn der wurde per 'checkout' aktiviert als Du das 'merge' gemacht hast) ist der obere Teil des Blocks (alles oberhalb von '======='), und die Version aus dem `iss53`-Branch sieht wie der darunter befindliche Teil aus. Um den Konflikt zu lösen, musst Du Dich entweder für einen der beiden Teile entscheiden oder Du ersetzt den Teil komplett: +Das heißt, die Version in HEAD (Deines 'master'-Branches, denn der wurde per 'checkout' aktiviert, als Du das 'merge' gemacht hast) ist der obere Teil des Blocks (alles oberhalb von '======='), und die Version aus dem `iss53`-Branch sieht wie der darunter befindliche Teil aus. Um den Konflikt zu lösen, musst Du Dich entweder für einen der beiden Teile entscheiden oder Du ersetzt den Teil komplett: - + + -Diese Lösung hat von beiden Teilen etwas und ich habe die Zeilen mit `<<<<<<<`, `=======`, und `>>>>>>>` komplett gelöscht. Nachdem Du alle problematischen Bereiche, in allen durch den Konflikt betroffenen Dateien, beseitigt hast, führe einfach `git add` für alle betroffenen Dateien aus und markieren sie damit als bereinigt. Dieses 'staging' der Dateien markiert sie für Git als bereinigt. -Wenn Du ein grafischen Tool zur Bereinigung benutzen willst, dann verwende `git mergetool`. Das welches ein passendes grafisches 'merge'-Tool startet und Dich durch die Konfliktbereiche führt: +Diese Lösung hat von beiden Teilen etwas und ich habe die Zeilen mit `<<<<<<<`, `=======`, und `>>>>>>>` komplett gelöscht. Nachdem Du alle problematischen Bereiche in allen von dem Konflikt betroffenen Dateien beseitigt hast, führe einfach `git add` für alle betroffenen Dateien aus und markiere sie damit als bereinigt. Dieses 'staging' der Dateien markiert sie für Git als bereinigt. +Wenn Du ein grafisches Tool zur Bereinigung benutzen willst, dann verwende `git mergetool`, welches ein passendes grafisches 'merge'-Tool startet und Dich durch die Konfliktbereiche führt: $ git mergetool - merge tool candidates: kdiff3 tkdiff xxdiff meld gvimdiff opendiff emerge vimdiff - Merging the files: index.html + + This message is displayed because 'merge.tool' is not configured. + See 'git mergetool --tool-help' or 'git help config' for more details. + 'git mergetool' will now attempt to use one of the following tools: + opendiff kdiff3 tkdiff xxdiff meld tortoisemerge gvimdiff diffuse diffmerge ecmerge p4merge araxis bc3 codecompare vimdiff emerge + Merging: + index.html Normal merge conflict for 'index.html': - {local}: modified - {remote}: modified + {local}: modified file + {remote}: modified file Hit return to start merge resolution tool (opendiff): - + -Wenn Du ein anderes Tool anstelle des Standardwerkzeug für ein 'merge' verwenden möchtest (Git verwendet in meinem Fall `opendiff`, da ich auf einem Mac arbeite), dann kannst Du alle unterstützten Werkzeuge oben – neben „merge tool candidates“ – aufgelistet sehen. Tippe einfach den Namen Deines gewünschten Werkzeugs ein. In Kapitel 7 besprechen wir, wie Du diesen Standardwert in Deiner Umgebung dauerhaft ändern kannst. +Wenn Du ein anderes Tool anstelle des Standardwerkzeugs für ein 'merge' verwenden möchtest (Git verwendet in meinem Fall `opendiff`, da ich auf einem Mac arbeite), dann kannst Du alle unterstützten Werkzeuge oben – unter „one of the following tools“ – aufgelistet sehen. Tippe einfach den Namen Deines gewünschten Werkzeugs ein. In Kapitel 7 besprechen wir, wie Du diesen Standardwert in Deiner Umgebung dauerhaft ändern kannst. @@ -436,42 +442,42 @@ Wenn Du das 'merge' Werkzeug beendest, fragt Dich Git, ob das Zusammenführen er Du kannst `git status` erneut ausführen, um zu sehen, ob alle Konflikte gelöst sind: $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # modified: index.html - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: index.html + -Wenn Du zufrieden bist und Du geprüft hast, dass alle Konflikte beseitigt wurden, kannst Du `git commit` ausführen um den 'merge commit' abzuschliessen. Die Standardbeschreibung für diese Art 'commit' sieht wie folgt aus: +Wenn Du zufrieden bist und Du geprüft hast, dass alle Konflikte beseitigt wurden, kannst Du `git commit` ausführen, um den 'merge commit' abzuschließen. Die Standardbeschreibung für diese Art 'commit' sieht wie folgt aus: Merge branch 'iss53' Conflicts: index.html # - # It looks like you may be committing a MERGE. + # It looks like you may be committing a merge. # If this is not correct, please remove the file - # .git/MERGE_HEAD + # .git/MERGE_HEAD # and try again. # -Wenn Du glaubst für zukünftige Betrachter des Commits könnte interessant sein warum Du getan hast, was Du getan hast, dann kannst Du der Commit-Beschreibung noch zusätzliche Informationen hinzufügen – sofern das nicht trivial erscheint. +Wenn Du glaubst, für zukünftige Betrachter des Commits könnte es hilfreich sein zu erklären, warum Du getan hast, was Du getan hast, dann kannst Du der Commit-Beschreibung noch zusätzliche Informationen hinzufügen, falls es nicht offensichtlich ist. ## Branch Management ## -Du weißt jetzt, wie Du Branches erstellen, mergen und löschen kannst. Wir schauen uns jetzt noch ein paar recht nützliche Tools für die Arbeit mit Branches an. +Du weißt jetzt, wie Du Branches erstellen, zusammenfügen und löschen kannst. Wir schauen uns jetzt noch ein paar recht nützliche Tools für die Arbeit mit Branches an. -Das Kommando `git branch` kann mehr, als nur Branches zu erstellen oder zu löschen. Wenn Du es ohne weitere Argumente ausführst, wird es Dir eine Liste mit Deinen aktuellen Branches anzeigen: +Die Anweisung `git branch` kann mehr, als nur Branches zu erstellen oder zu löschen. Wenn Du es ohne weitere Argumente ausführst, wird es Dir eine Liste mit Deinen aktuellen Branches anzeigen: $ git branch iss53 @@ -487,9 +493,9 @@ Das `*` vor dem `master`-Branch bedeutet, dass dies der gerade ausgecheckte Bran * master 7a98805 Merge branch 'iss53' testing 782fd34 add scott to the author list in the readmes - + -Mit einer weiteren nützlichen Option kannst Du herausfinden, in welchem Zustand Deine Branches sind: welche der Branches wurden bereits in den aktuellen Branch gemergt und welche wurden es nicht. Die Optionen heißen `--merged` und `--no-merged` und sind seit Version 1.5.6 in Git dabei. Um herauszufinden, welche Branches schon in den aktuell ausgecheckten gemergt wurden, kannst Du einfach `git branch --merged` aufrufen: +Mit einer weiteren nützlichen Option kannst Du herausfinden, in welchem Zustand Deine Branches sind: welche der Branches wurden bereits in den aktuellen Branch gemergt und welche wurden es nicht. Für diesen Zweck gibt es in Git die Optionen `--merged` und `--no-merged`. Um herauszufinden, welche Branches schon in den aktuell ausgecheckten gemergt wurden, kannst Du einfach `git branch --merged` aufrufen: $ git branch --merged iss53 @@ -511,34 +517,34 @@ Um alle Branches zu sehen, welche noch nicht gemergte Änderungen enthalten, kan Die Liste zeigt Dir den anderen Branch. Er enthält Arbeit, die noch nicht gemergt wurde. Der Versuch, den Branch mit `git branch -d` zu löschen schlägt fehl: $ git branch -d testing - error: The branch 'testing' is not an ancestor of your current HEAD. - If you are sure you want to delete it, run `git branch -D testing`. + error: The branch 'testing' is not fully merged. + If you are sure you want to delete it, run 'git branch -D testing'. -Wenn Du den Branch trotzdem löschen willst – und damit alle Änderungen dieses Branches verlieren – kannst Du das mit `git branch -D testing` machen. +Wenn Du den Branch trotzdem löschen und damit alle Änderungen dieses Branches verlieren willst, kannst Du das mit `git branch -D testing` machen. ## Branching Workflows ## -Jetzt da Du die Grundlagen von 'branching' und 'merging' kennst, fragst Du Dich sicher, was Du damit anfangen kannst. In diesem Abschnitt werden wir uns typische Workflows anschauen, die dieses leichtgewichtige 'branching' möglich macht. Und Du kannst dann entscheiden, ob Du es in Deinem eigene Entwicklungszyklus verwenden willst. +Jetzt, da Du die Grundlagen von 'branching' und 'merging' kennst, fragst Du Dich sicher, was Du damit anfangen kannst. In diesem Abschnitt werden wir uns typische Workflows anschauen, die dieses leichtgewichtige 'branching' möglich macht. Und Du kannst dann entscheiden, ob Du es in Deinem eigenen Entwicklungszyklus verwenden willst. ### Langfristige Branches ### -Da Git das einfachen 3-Wege-'merge' verwendet, ist häufiges Zusammenführen von einer Branch in eine andere über einen langen Zeitraum generell einfach zu bewerkstelligen. Das heisst, Du kann mehrere Branches haben, die alle offen sind und auf unterschiedlichen Ebenen Deines Entwicklungszyklus verwendung finden, und diese regelmäßig ineinander zusammenführen. +Da Git das einfache 3-Wege-'merge' verwendet, ist häufiges Zusammenführen von einem Branch in einen anderen über einen langen Zeitraum generell einfach zu bewerkstelligen. Das heißt, Du kannst mehrere Branches haben, die immer offen sind und die Du für unterschiedliche Stadien Deines Entwicklungszyklus verwendest, und Du kannst regelmäßig welche von diesen mit anderen zusammenführen. -Viele Git Entwickler verfolgen mit ihrem Workflow den Ansatz nur den stabilen Code in dem `master`-Branch zu halten – möglicherweise auch nur Code, der released wurde oder werden kann. Sie betreiben parallel einen anderen Branch zum Arbeiten oder Testen. Wenn dieser paralelle Zweig einen stabilen Status erreicht, kann er mit dem `master`-Branch zusammengeführt werden. Dies findet bei Themen bezogenen Branches (kurzfristigen Branches, wie der zuvor genante `iss53`-Branch) Anwendung, um sicherzustellen, dass dieser die Tests besteht und keine Fehler verursacht. +Viele Git Entwickler verfolgen mit ihrem Workflow den Ansatz, nur den stabilen Code in dem `master`-Branch zu halten – möglicherweise auch nur Code, der released wurde oder werden kann. Sie betreiben parallel einen anderen Branch zum Arbeiten oder Testen. Wenn dieser parallele Zweig einen stabilen Status erreicht, kann er mit dem `master`-Branch zusammengeführt werden. Dies findet bei themenbezogenen Branches (kurzfristigen Branches, wie der zuvor genannte `iss53`-Branch) Anwendung, um sicherzustellen, dass dieser die Tests besteht und keine Fehler verursacht. -In Realität reden wir über sich bewegende Zeiger, die den Commit-Verlauf weiterwandern. Die stabilen Branches liegen unten und die bleeding-edge Branches weiter oben in der Zeitlinie (siehe Abbildung 3-18). +Eigentlich reden wir gerade über Zeiger, die in der Reihe Deiner Commits aufsteigen. Die stabilen Branches liegen weiter unten und die bleeding-edge Branches weiter oben in diesem Verlauf (siehe Abbildung 3-18). @@ -547,34 +553,34 @@ Abbildung 3-18. Stabilere Branches sind generell weiter unten im Entwicklungsver -Es ist leichter sich die verschiedenen Branches als Arbeitsdepots vorzustellen, in denen Sätze von Commits in stabilere Depots aufsteigen, sobald sie ausreichend getestet wurden (siehe Abbildung 3-19). +Es ist leichter, sich die verschiedenen Branches als Arbeitsdepots vorzustellen, in denen Sätze von Commits in stabilere Depots aufsteigen, sobald sie ausreichend getestet wurden (siehe Abbildung 3-19). Insert 18333fig0319.png Abbildung 3-19. Es könnte hilfreich sein, sich die Branches als Depots vorzustellen. - + + -Das lässt sich für beliebig viele Stabilitätsabstufungen umsetzen. Manche größeren Projekte haben auch einen `proposed` (Vorgeschlagen) oder `pu` (proposed updates – vorgeschlagene Updates) Zweig mit Branches die vielleicht noch nicht bereit sind in den `next`- oder `master`-Branch integriert zu werden. Die Idee dahinter ist, dass Deine Branches verschiedene Stabilitätsabstufungen repräsentieren. Sobald sie eine stabilere Stufe erreichen, werden sie in den nächsthöheren Branch vereinigt. +Das lässt sich für beliebig viele Stabilitätsabstufungen umsetzen. Manche größeren Projekte haben auch einen `proposed` (vorgeschlagenen) oder `pu` (proposed updates – vorgeschlagene Updates) Zweig mit Branches, die vielleicht noch nicht bereit sind, in den `next`- oder `master`-Branch integriert zu werden. Die Idee dahinter ist, dass Deine Branches verschiedene Stabilitätsabstufungen repräsentieren. Sobald sie eine stabilere Stufe erreichen, werden sie mit dem nächsthöheren Branch zusammengeführt. -Nochmal, langfristig verschiedene Branches paralell laufen zu lassen ist nicht notwendig, aber oft hilfreich. Insbesondere wenn man es mit sehr großen oder komplexen Projekten zu tun hat. +Nochmal, langfristig verschiedene Branches parallel laufen zu lassen, ist nicht notwendig, aber oft hilfreich, insbesondere wenn man es mit sehr großen oder komplexen Projekten zu tun hat. ### Themen-Branches ### -Themen-Branches sind in jedem Projekt nützlich, egal bei welcher Größe. Ein Themen-Branch ist ein kurzlebiger Zweig der für eine spezielle Aufgabe oder ähnliche Arbeiten erstellt und benutzt wird. Das ist vielleicht etwas was Du noch nie zuvor mit einem Versionierungssystem gemacht hast, weil es normalerweise zu aufwändig und mühsam ist Branches zu erstellen und zusammenzuführen. Mit Git ist es allerdings vollkommen geläufig mehrmals am Tag Branches zu erstellen, an ihnen zu arbeiten, sie zusammenzuführen und sie anschließend wieder zu löschen. +Themen-Branches sind in jedem Projekt nützlich, egal bei welcher Größe. Ein Themen-Branch ist ein kurzlebiger Zweig, der für eine spezielle Aufgabe oder ähnliche Arbeiten erstellt und benutzt wird. Das ist vielleicht etwas, was Du noch nie zuvor mit einem Versionierungssystem gemacht hast, weil es normalerweise zu aufwändig und mühsam ist, Branches zu erstellen und zusammenzuführen. Mit Git ist es allerdings vollkommen geläufig, mehrmals am Tag Branches zu erstellen, an ihnen zu arbeiten, sie zusammenzuführen und sie anschließend wieder zu löschen. -Du hast das im letzten Abschnitt an den von Dir erstellten `iss53`- und `hotfix`-Branches gesehen. Du hast mehrere Commits auf sie angewendet und sie unmittelbar nach Zusammenführung mit Deinem Hauptzweig gelöscht. Diese Technik erlaubt es Dir schnell und vollständig den Kontext zu wechseln. Da Deine Arbeit in verschiedene Depots aufgeteilt ist, in denen alle Änderungen unter die Thematik dieses Branches fallen, ist es leichter nachzuvollziehen was bei Code-Überprüfungen und ähnlichem geschehen ist. +Du hast das im letzten Abschnitt an den von Dir erstellten `iss53`- und `hotfix`-Branches gesehen. Du hast mehrere Commits auf sie angewendet und sie unmittelbar nach Zusammenführung mit Deinem Hauptzweig gelöscht. Diese Technik erlaubt es Dir, schnell und vollständig den Kontext zu wechseln. Da Deine Arbeit in verschiedene Depots aufgeteilt ist, in denen alle Änderungen unter die Thematik dieses Branches fallen, ist es leichter nachzuvollziehen, was bei Code-Überprüfungen und ähnlichem geschehen ist. Du kannst die Änderungen darin für Minuten, Tage oder Monate aufbewahren und sie einfließen lassen, wenn diese fertig sind, ungeachtet der Reihenfolge, in welcher diese erstellt oder bearbeitet wurden. -Stell Dir vor, Du arbeitest ein bisschen (in `master`), erstellst mal eben einen Branch für einen Fehler (`iss91`), arbeitest an dem für eine Weile, erstellst einen zweiten Branch um eine andere Problemlösung für den selben Fehler auszuprobieren (`iss91v2`), wechselst zurück zu Deinem MASTER-Branch, arbeitest dort ein bisschen und machst dann einen neuen Branch für etwas, wovon Du nicht weißt ob's eine gute Idee ist (`dumbidea`-Branch). Dein Commit-Verlauf wird wie in Abbildung 3-20 aussehen. +Stell Dir vor, Du arbeitest ein bisschen (in `master`), erstellst mal eben einen Branch für einen Fehler (`iss91`), arbeitest an dem für eine Weile, erstellst einen zweiten Branch, um eine andere Problemlösung für den selben Fehler auszuprobieren (`iss91v2`), wechselst zurück zu Deinem master-Branch, arbeitest dort ein bisschen und machst dann einen neuen Branch für etwas, wovon Du nicht weißt, ob es eine gute Idee ist (`dumbidea`-Branch). Dein Commit-Verlauf wird wie in Abbildung 3-20 aussehen. @@ -583,7 +589,7 @@ Abbildung 3-20. Dein Commit-Verlauf mit verschiedenen Themen-Branches. -Nun, sagen wir Du hast Dich entschieden die zweite Lösung des Fehlers (`iss91v2`) zu bevorzugen, außerdem hast den `dumbidea`-Branch Deinen Mitarbeitern gezeigt und es hat sich herausgestellt das er genial ist. Du kannst also den ursprünglichen `iss91`-Branch (unter Verlust der Commits C5 und C6) wegschmeißen und die anderen Beiden vereinen. Dein Verlauf sieht dann aus wie in Abbildung 3-21. +Nun, sagen wir, Du hast Dich entschieden, die zweite Lösung des Fehlers (`iss91v2`) zu bevorzugen, außerdem hast den `dumbidea`-Branch Deinen Mitarbeitern gezeigt und es hat sich herausgestellt, dass er genial ist. Du kannst also den ursprünglichen `iss91`-Branch (unter Verlust der Commits C5 und C6) wegwerfen und die anderen beiden einfließen lassen. Dein Verlauf sieht dann aus wie in Abbildung 3-21. @@ -592,22 +598,22 @@ Abbildung 3-21. Dein Verlauf nach Zusammenführung von `dumbidea` und `iss91v2`. -Es ist wichtig sich daran zu erinnern, dass alle diese Branches nur lokal existieren. Wenn Du Verzweigungen schaffst (branchst) und wieder zusammenführst (mergest), findet dies nur in Deinem Git-Repository statt – es findet keine Server-Kommunikation statt. +Es ist wichtig, sich daran zu erinnern, dass alle diese Branches nur lokal existieren. Wenn Du Verzweigungen schaffst (branchst) und wieder zusammenführst (mergest), findet dies nur in Deinem Git-Repository statt – es findet keine Server-Kommunikation statt. ## Externe Branches ## -Externe (Remote) Branches sind Referenzen auf den Zustand der Branches in Deinen externen Repositorys. Es sind lokale Branches die Du nicht verändern kannst, sie werden automatisch verändert wann immer Du eine Netzwerkoperation durchführst. Externe Branches verhalten sich wie Lesezeichen, um Dich daran zu erinnern an welcher Position sich die Branches in Deinen externen Repositories befanden, als Du Dich zuletzt mit ihnen verbunden hattest. +Externe (Remote) Branches sind Referenzen auf den Zustand der Branches in Deinen externen Repositorys. Sie sind lokale Branches, die Du nicht verändern kannst, sie werden automatisch verändert, wann immer Du eine Netzwerkoperation durchführst. Externe Branches verhalten sich wie Lesezeichen, um Dich daran zu erinnern, an welcher Position sich die Branches in Deinen externen Repositorys befanden, als Du Dich zum letzten Mal mit ihnen verbunden hattest. -Externe Branches besitzen die Schreibweise `(Repository)/(Branch)`. Wenn Du beispielsweise wissen möchtest wie der `master`-Branch in Deinem `origin`-Repository ausgesehen hat, als Du zuletzt Kontakt mit ihm hattest, dann würdest Du den `origin/master`-Branch überprüfen. Wenn Du mit einem Mitarbeiter an einer Fehlerbehebung gearbeitet hast, und dieser bereits einen `iss53`-Branch hochgeladen hat, besitzt Du möglicherweise Deinen eigenen lokalen `iss53`-Branch. Der Branch auf dem Server würde allerdings auf den Commit von `origin/iss53` zeigen. +Externe Branches besitzen die Schreibweise `(Repository)/(Branch)`. Wenn Du beispielsweise wissen möchtest, wie der `master`-Branch in Deinem `origin`-Repository ausgesehen hat, als Du zuletzt Kontakt mit ihm hattest, dann würdest Du den `origin/master`-Branch überprüfen. Wenn Du mit einem Mitarbeiter an einer Fehlerbehebung gearbeitet hast und dieser bereits einen `iss53`-Branch hochgeladen hat, besitzt Du möglicherweise Deinen eigenen lokalen `iss53`-Branch. Der Branch auf dem Server würde allerdings auf den Commit von `origin/iss53` zeigen. -Das kann ein wenig verwirrend sein, lass uns also ein Besipiel betrachten. Nehmen wir an Du hättest in Deinem Netzwerk einen Git-Server mit der Adresse `git.ourcompany.com`. Wenn Du von ihm klonst, nennt Git ihn automatisch `origin` für dich, lädt all seine Daten herunter, erstellt einen Zeiger an die Stelle wo sein `master`-Branch ist und benennt es lokal `origin/master`; und er ist unveränderbar für dich. Git gibt Dir auch einen eigenen `master`-Branch mit der gleichen Ausgangsposition wie origins `master`-Branch, damit Du einen Punkt für den Beginn Deiner Arbeiten hast (siehe Abbildung 3-22). +Das kann ein wenig verwirrend sein, lass uns also ein Besipiel betrachten. Nehmen wir an, Du hättest in Deinem Netzwerk einen Git-Server mit der Adresse `git.ourcompany.com`. Wenn Du von diesem klonst, nennt Git ihn automatisch `origin` für Dich, lädt all seine Daten herunter, erstellt einen Zeiger zur der Stelle, wo sein `master`-Branch ist und benennt es lokal `origin/master`; und er ist unveränderbar für Dich. Git gibt Dir auch einen eigenen `master`-Branch mit der gleichen Ausgangsposition wie origins `master`-Branch, damit Du einen Punkt für den Beginn Deiner Arbeiten hast (siehe Abbildung 3-22). @@ -616,25 +622,25 @@ Abbildung 3-22. Ein 'git clone' gibt Dir Deinen eigenen `master`-Branch und `ori -Wenn Du ein wenig an Deinem lokalen `master`-Branch arbeitest und unterdessen jemand etwas zu `git.ourcompany.com` herauflädt, verändert er damit dessen `master`-Branch und eure Arbeitsverläufe entwickeln sich unterschiedlich. Indes bewegt sich Dein `origin/master`-Zeiger nicht, solange Du keinen Kontakt mit Deinem `origin`-Server aufnimmst (siehe Abbildung 3-23). +Wenn Du ein wenig an Deinem lokalen `master`-Branch arbeitest und in der Zwischenzeit ein anderer etwas zu `git.ourcompany.com` herauflädt und damit den `master`-Branch auf dem externen Server aktualisiert, dann entwickeln sich Eure Arbeitsverläufe unterschiedlich. Außerdem bewegt sich Dein `origin/master`-Zeiger nicht, solange Du keinen Kontakt mit Deinem `origin`-Server aufnimmst (siehe Abbildung 3-23). Insert 18333fig0323.png -Abbildung 3-23. Lokales Arbeiten, während jemand auf Deinen externen Server hochlädt, lässt jeden Änderungsverlauf unterschiedlich weiterentwickeln. +Abbildung 3-23. Lokal zu arbeiten, während ein anderer auf Deinen externen Server hochlädt, führt zu unterschiedlichen Verläufen. -Um Deine Arbeit abzugleichen, führe ein `git fetch origin`-Kommando aus. Das Kommando schlägt nach welcher Server `orgin` ist (in diesem Fall `git.ourcompany.com`), holt alle Daten die Dir bisher fehlen und aktualisiert Deine lokale Datenbank, indem es Deinen `orgin/master`-Zeiger auf seine neue aktuellere Position bewegt (siehe Abbildung 3-24). +Um Deine Arbeit abzugleichen, führe die Anweisung `git fetch origin` aus. Die Anweisung schlägt nach, welcher Server `orgin` ist (in diesem Fall `git.ourcompany.com`), holt alle Daten, die Dir bisher fehlen und aktualisiert Deine lokale Datenbank, indem es Deinen `orgin/master`-Zeiger auf seine neue aktuellere Position bewegt (siehe Abbildung 3-24). Insert 18333fig0324.png -Abbildung 3-24. Das `git fetch`-Kommando aktualisiert Deine externen Referenzen. +Abbildung 3-24. Die Anweisung `git fetch` aktualisiert Deine externen Referenzen. -Um zu demonstrieren wie Branches auf verschiedenen Remote-Servern aussehen, stellen wir uns vor, dass Du einen weiteren internen Git-Server besitzt, welcher nur von einem Deiner Sprint-Teams zur Entwicklung genutzt wird. Diesen Server erreichen wir unter `git.team1.ourcompany.com`. Du kannst ihn, mit dem Git-Kommando `git remote add` – wie in Kapitel 2 beschrieben, Deinem derzeitigen Arbeitsprojekt als weiteren Quell-Server hinzufügen. Gib dem Remote-Server den Namen `teamone`, welcher nun als Synonym für die ausgeschriebene Internetadresse dient (siehe Abbildung 3-25). +Um zu demonstrieren, wie Branches auf verschiedenen Remote-Servern aussehen, stellen wir uns vor, dass Du einen weiteren internen Git-Server besitzt, welcher nur von einem Deiner Sprint-Teams zur Entwicklung genutzt wird. Diesen Server erreichen wir unter `git.team1.ourcompany.com`. Du kannst ihn mit der Git-Anweisung `git remote add`, wie in Kapitel 2 beschrieben, Deinem derzeitigen Arbeitsprojekt als weiteren Quell-Server hinzufügen. Gib dem Remote-Server den Namen `teamone`, welcher nun als Synonym für die ausgeschriebene Internetadresse dient (siehe Abbildung 3-25). @@ -643,7 +649,7 @@ Abbildung 3-25. Einen weiteren Server als Quelle hinzufügen. -Nun kannst Du einfach `git fetch teamone` ausführen um alles vom Server zu holen was Du noch nicht hast. Da der Datenbestand auf dem Teamserver ein Teil der Informationen auf Deinem `origin`-Server ist, holt Git keine Daten, erstellt allerdings einen Remote-Branch namens `teamone/master`, der auf den gleichen Commit wie `teamone`s `master`-Branch zeigt (siehe Abbildung 3-26). +Nun kannst Du einfach `git fetch teamone` ausführen, um alles vom Server zu holen, was Du noch nicht hast. Da der Datenbestand auf dem Teamserver ein Teil der Informationen auf Deinem `origin`-Server ist, holt Git keine Daten, erstellt allerdings einen Remote-Branch namens `teamone/master`, der auf den gleichen Commit wie `teamone`s `master`-Branch zeigt (siehe Abbildung 3-26). @@ -655,7 +661,7 @@ Abbildung 3-26. Du bekommst eine lokale Referenz auf `teamone`s `master`-Branch. -Wenn Du einen Branch mit der Welt teilen möchtest, musst Du ihn auf einen externen Server laden, auf dem Du Schreibrechte besitzt. Deine lokalen Zweige werden nicht automatisch mit den Remote-Servern synchronisiert wenn Du etwas änderst – Du musst die zu veröffentlichenden Branches explizit hochladen (pushen). Auf diesem Weg kannst Du an privaten Zweigen arbeiten die Du nicht veröffentlichen möchtest, und nur die Themen-Branches replizieren an denen Du gemeinsam mit anderen entwickeln möchtest. +Wenn Du einen Branch mit der Welt teilen möchtest, musst Du ihn auf einen externen Server laden, auf dem Du Schreibrechte besitzt. Deine lokalen Zweige werden nicht automatisch mit den Remote-Servern synchronisiert, wenn Du etwas änderst – Du musst die zu veröffentlichenden Branches explizit hochladen (pushen). Auf diesem Weg kannst Du an privaten Zweigen arbeiten, die Du nicht veröffentlichen möchtest, und nur die Themen-Branches replizieren, an denen Du gemeinsam mit anderen entwickeln möchtest. @@ -671,11 +677,11 @@ Wenn Du einen Zweig namens `serverfix` besitzt, an dem Du mit anderen arbeiten m -Hierbei handelt es sich um eine Abkürzung. Git erweitert die `serverfix`-Branchbezeichnung automatisch zu `refs/heads/serverfix:refs/heads/serverfix`, was soviel bedeutet wie “Nimm meinen lokalen `serverfix`-Branch und aktualisiere damit den `serverfix`-Branch auf meinem externen Server”. Wir werden den `refs/heads/`-Teil in Kapitel 9 noch näher beleuchten, Du kannst ihn aber in der Regel weglassen. Du kannst auch `git push origin serverfix:serverfix` ausführen, was das gleiche bewirkt – es bedeutet “Nimm meinen `serverfix` und mach ihn zum externen `serverfix`”. Du kannst dieses Format auch benutzen um einen lokalen Zweig in einen externen Branch mit anderem Namen zu laden. Wenn Du ihn auf dem externen Server nicht `serverfix` nennen möchtest, könntest Du stattdessen `git push origin serverfix:awesomebranch` ausführen um Deinen lokalen `serverfix`-Branch in den `awesomebranch`-Zweig in Deinem externen Projekt zu laden. +Hierbei handelt es sich um eine Abkürzung. Git erweitert die `serverfix`-Branchbezeichnung automatisch zu `refs/heads/serverfix:refs/heads/serverfix`, was soviel bedeutet wie “Nimm meinen lokalen `serverfix`-Branch und aktualisiere damit den `serverfix`-Branch auf meinem externen Server”. Wir werden den `refs/heads/`-Teil in Kapitel 9 noch näher beleuchten, Du kannst ihn aber in der Regel weglassen. Du kannst auch `git push origin serverfix:serverfix` ausführen, was das Gleiche bewirkt – es bedeutet “Nimm meinen `serverfix` und mach ihn zum externen `serverfix`”. Du kannst dieses Format auch benutzen, um einen lokalen Zweig in einen externen Branch mit anderem Namen zu laden. Wenn Du ihn auf dem externen Server nicht `serverfix` nennen möchtest, könntest Du stattdessen `git push origin serverfix:awesomebranch` ausführen, um Deinen lokalen `serverfix`-Branch in den `awesomebranch`-Zweig in Deinem externen Projekt zu laden. -Das nächste Mal wenn einer Deiner Mitarbeiter den aktuellen Status des Git-Projektes vom Server abruft, wird er eine Referenz, auf den externen Branch `origin/serverfix`, unter dem Namen `serverfix` erhalten: +Das nächste Mal, wenn einer Deiner Mitarbeiter den aktuellen Status des Git-Projektes vom Server abruft, wird er eine Referenz auf den externen Branch `origin/serverfix` unter dem Namen `serverfix` erhalten: $ git fetch origin remote: Counting objects: 20, done. @@ -687,11 +693,11 @@ Das nächste Mal wenn einer Deiner Mitarbeiter den aktuellen Status des Git-Proj -Es ist wichtig festzuhalten, dass Du mit Abrufen eines neuen externen Branches nicht automatisch eine lokale, bearbeitbare Kopie derselben erhältst. Mit anderen Worten, in diesem Fall bekommst Du keinen neuen `serverfix`-Branch – sondern nur einen `origin/serverfix`-Zeiger den Du nicht verändern kannst. +Es ist wichtig festzuhalten, dass Du mit Abrufen eines neuen externen Branches nicht automatisch eine lokale, bearbeitbare Kopie desselben erhältst. Mit anderen Worten, in diesem Fall bekommst Du keinen neuen `serverfix`-Branch – sondern nur einen `origin/serverfix`-Zeiger, den Du nicht verändern kannst. -Um diese referenzierte Arbeit mit Deinem derzeitigen Arbeitsbranch zusammenzuführen kannst Du `git merge origin/serverfix` ausführen. Wenn Du allerdings Deine eigene Arbeitskopie des `serverfix`-Branches erstellen möchtest, dann kannst Du diesen auf Grundlage des externen Zweiges erstellen: +Um diese referenzierte Arbeit mit Deinem derzeitigen Arbeitsbranch zusammenzuführen, kannst Du `git merge origin/serverfix` ausführen. Wenn Du allerdings Deine eigene Arbeitskopie des `serverfix`-Branches erstellen möchtest, dann kannst Du diesen auf Grundlage des externen Zweiges erstellen: $ git checkout -b serverfix origin/serverfix Branch serverfix set up to track remote branch refs/remotes/origin/serverfix. @@ -706,25 +712,25 @@ Dies erstellt Dir einen lokalen bearbeitbaren Branch mit der Grundlage des `orig -Das Auschecken eines lokalen Branches von einem Remote-Branch erzeugt automatisch einen sogenannten _Tracking-Branch_. Tracking Branches sind lokale Branches mit einer direkten Beziehung zu dem Remote-Zweig. Wenn Du Dich in einem Tracking-Branch befindest und `git push` eingibst, weiß Git automatisch zu welchem Server und Repository es pushen soll. Ebenso führt `git pull` in einem dieser Branches dazu, dass alle entfernten Referenzen gefetched und automatisch in den Zweig gemerged werden. +Das Auschecken eines lokalen Branches von einem Remote-Branch erzeugt automatisch einen sogenannten _Tracking-Branch_. Tracking Branches sind lokale Branches mit einer direkten Beziehung zu dem Remote-Zweig. Wenn Du Dich in einem Tracking-Branch befindest und `git push` eingibst, weiß Git automatisch, zu welchem Server und Repository es pushen soll. Ebenso führt `git pull` in einem dieser Branches dazu, dass alle entfernten Referenzen gefetched und automatisch in den Zweig gemerged werden. -Wenn Du ein Repository klonst, wird automatisch ein `master`-Branch erzeugt, welcher `origin/master` verfolgt. Deshalb können `git push` und `git pull` ohne weitere Argumente aufgerufen werden. Du kannst natürlich auch eigene Tracking-Branches erzeugen – welche die nicht Zweige auf `origin` und dessen `master`-Branch verfolgen. Der einfachste Fall ist das bereits gesehene Beispiel in welchem Du `git checkout -b [branch] [remotename]/[branch]` ausführst. Mit der Git-Version 1.6.2 oder später kannst Du auch die `--track`-Kurzvariante nutzen: +Wenn Du ein Repository klonst, wird automatisch ein `master`-Branch erzeugt, welcher `origin/master` verfolgt. Deshalb können `git push` und `git pull` ohne weitere Argumente aufgerufen werden. Du kannst natürlich auch eigene Tracking-Branches erzeugen – welche die nicht Zweige auf `origin` und dessen `master`-Branch verfolgen. Der einfachste Fall ist das bereits gesehene Beispiel, in welchem Du `git checkout -b [branch] [remotename]/[branch]` ausführst. Mit der Git-Version 1.6.2 oder später kannst Du auch die `--track`-Kurzvariante nutzen: $ git checkout --track origin/serverfix - Branch serverfix set up to track remote branch refs/remotes/origin/serverfix. - Switched to a new branch "serverfix" + Branch serverfix set up to track remote branch serverfix from origin. + Switched to a new branch 'serverfix' -Um einen lokalen Branch mit einem anderem Namen als der Remote-Branch, kannst Du einfach die erste Varianten mit einem neuen lokalen Branch-Namen: +Um einen lokalen Branch zu erzeugen mit einem anderen Namen als dem des Remote-Branches, kannst Du einfach die erste Variante mit einem neuen lokalen Branch-Namen verwenden: $ git checkout -b sf origin/serverfix - Branch sf set up to track remote branch refs/remotes/origin/serverfix. - Switched to a new branch "sf" + Branch sf set up to track remote branch serverfix from origin. + Switched to a new branch 'sf' - + Nun wird Dein lokaler Branch `sf` automatisch push und pull auf `origin/serverfix` durchführen. @@ -733,7 +739,7 @@ Nun wird Dein lokaler Branch `sf` automatisch push und pull auf `origin/serverfi -Stellen wir uns Du bist fertig mit Deinem Remote-Branch – sagen wir Deine Mitarbeiter und Du, Ihr seid fertig mit einer neuen Funktion und habt sie in den entfernten `master`-Branch (oder in welchem Zweig Ihr sonst den stabilen Code ablegt) gemerged. Du kannst einen Remote-Branch mit der unlogischen Syntax `git push [remotename] :[branch]` löschen. Wenn Du Deinen `serverfix`-Branch vom Server löschen möchtest, führe folgendes aus: +Stellen wir uns vor, Du bist fertig mit Deinem Remote-Branch – sagen wir Deine Mitarbeiter und Du, Ihr seid fertig mit einer neuen Funktion und habt sie in den entfernten `master`-Branch (oder in welchem Zweig Ihr sonst den stabilen Code ablegt) gemerged. Dann kannst Du den Remote-Branch löschen, indem Du die recht stumpfsinnige Syntax `git push [remotename] :[branch]` benutzt. Wenn Du Deinen `serverfix`-Branch vom Server löschen möchtest, führe folgendes aus: $ git push origin :serverfix To git@github.com:schacon/simplegit.git @@ -741,21 +747,21 @@ Stellen wir uns Du bist fertig mit Deinem Remote-Branch – sagen wir Deine Mita -Boom. Kein Zweig mehr auf Deinem Server. Du möchtest Dir diese Seite vielleicht markieren, weil Du dieses Kommando noch benötigen wirst und man leicht dessen Syntax vergisst. Ein Weg sich an dieses Kommando zu erinnern führt über die `git push [remotename] [localbranch]:[remotebranch]`-Snytax, welche wir bereits behandelt haben. Wenn Du den `[localbranch]`-Teil weglässt, dann sagst Du einfach „Nimm nichts von meiner Seite und mach es zu `[remotebranch]`“. +Boom. Kein Zweig mehr auf Deinem Server. Du möchtest Dir diese Seite vielleicht markieren, weil Du diese Anweisung noch benötigen wirst und man leicht deren Syntax vergisst. Ein Weg, sich an diese Anweisung zu erinnern, führt über die `git push [remotename] [localbranch]:[remotebranch]`-Snytax, welche wir bereits behandelt haben. Wenn Du den `[localbranch]`-Teil weglässt, dann sagst Du einfach „Nimm nichts von meiner Seite und mach es zu `[remotebranch]`“. ## Rebasing ## -Es gibt in Git zwei Wege um Änderungen von einem Branch in einen anderen zu überführen: das `merge` und das `rebase`-Kommando. In diesem Abschnitt wirst Du kennenlernen was Rebasing ist, wie Du es anwendest, warum es ein verdammt abgefahrenes Werkzeug ist und wann Du es lieber nicht einsetzen möchtest. +Es gibt in Git zwei Wege, um Änderungen von einem Branch in einen anderen zu überführen: `merge` und `rebase`. In diesem Abschnitt wirst Du erfahren, was Rebasing ist, wie Du es anwendest, warum es ein verdammt abgefahrenes Werkzeug ist und bei welchen Gelegenheiten Du es besser nicht einsetzen solltest. ### Der einfache Rebase ### -Wenn Du zu einem früheren Beispiel aus dem Merge-Kapitel zurückkehrst (siehe Abbildung 3-27), wirst Du sehen, dass Du Deine Arbeit auf zwei unterschiedliche Branches aufgeteilt hast. +Wenn Du zu einem früheren Beispiel aus dem Merge-Kapitel zurückkehrst (siehe Abbildung 3-27), kannst Du sehen, dass Du Deine Arbeit aufgeteilt und Commits auf zwei unterschiedlichen Branches erstellt hast. @@ -764,16 +770,16 @@ Abbildung 3-27. Deine initiale Commit-Historie zum Zeitpunkt der Aufteilung. -Der einfachste Weg um Zweige zusammenzuführen ist, wie bereits behandelt, das `merge`-Kommando. Es produziert einen Drei-Wege-Merge zwischen den beiden letzten Branch-Zuständen (C3 und C4) und ihrem wahrscheinlichsten Vorgänger (C2). Es produziert seinerseits einen Schnappschuss des Projektes (und einen Commit), wie in Abbildung 3-28 dargestellt. +Der einfachste Weg, um Zweige zusammenzuführen, ist, wie bereits behandelt, die `merge`-Anweisung. Sie führt einen Drei-Wege-Merge durch zwischen den beiden letzten Branch-Zuständen (C3 und C4) und dem letzen gemeinsamen Vorgänger (C2) der beiden, erstellt einen neuen Schnappschuss (und einen Commit), wie in Abbildung 3-28 dargestellt. Insert 18333fig0328.png -Abbildung 3-28. Das Zusammenführen eines Branches um die verschiedenen Arbeitsfortschritte zu integrieren. +Abbildung 3-28. Zusammenführen von Branches, um die verschiedenen Arbeitsfortschritte zu integrieren. -Wie auch immer, es gibt noch einen anderen Weg: Du kannst den Patch der Änderungen – den wir in C3 eingeführt haben – über C4 anwenden. Dieses Vorgehen nennt man in Git _rebasing_. Mit dem `rebase`-Kommando kannst Du alle Änderungen die auf einem Branch angewendet wurden auf einen anderen Branch erneut anwenden. +Allerdings gibt es noch einen anderen Weg: Du kannst den Patch der Änderungen, den wir in C3 eingeführt haben, nehmen und erneut anwenden auf C4. Dieses Vorgehen nennt man in Git _rebasing_. Mit der `rebase`-Anweisung kannst Du alle Änderungen, die an einem Branch vorgenommen wurden, auf einen anderen Branch erneut anwenden. @@ -786,12 +792,12 @@ In unserem Beispiel würdest Du folgendes ausführen: -Dies funktioniert, indem Git zu dem gemeinsamen/allgemeinen Vorfahren [gemeinsamer Vorfahr oder der Ursprung der beiden Branches?] der beiden Branches (des Zweiges auf dem Du arbeitest und des Zweiges auf den Du _rebasen_ möchtest) geht, die Differenzen jedes Commits des aktuellen Branches ermittelt und temporär in einer Datei ablegt. Danach wird der aktuelle Branch auf den Schnittpunkt der beiden Zweige zurückgesetzt und alle zwischengespeicherte Commits nacheinander auf den Zielbranch angewendet. Die Abbildung 3-29 bildet diesen Prozess ab. +Dies funktioniert, indem Git zum letzten gemeinsamen Vorfahren der beiden Branches (der, auf dem Du arbeitest, und jener, auf den Du _rebasen_ möchtest) geht, dann die Informationen zu den Änderungen (diffs) sammelt, welche seit dem bei jedem einzelen Commit des aktuellen Branches gemacht wurden, diese in temporären Dateien speichert, den aktuellen Branch auf den gleichen Commit setzt wie den Branch, auf den Du _rebasen_ möchtest und dann alle Änderungen erneut durchführt. Die Abbildung 3-29 bildet diesen Prozess ab. Insert 18333fig0329.png -Abbildung 3-29. Rebasen der Änderungen durch C3 auf den Zweig C4. +Abbildung 3-29. Rebasen der in C3 durchgeführten Änderungen auf C4. @@ -804,22 +810,22 @@ Abbildung 3-30. Fast-forward des Master-Branches. -Nun ist der Schnappschuss, auf den C3' zeigt, exakt der gleiche, wie der auf den C5 in dem Merge-Beispiel gezeigt hat. Bei dieser Zusammenführung entsteht kein unterschiedliches Produkt, durch Rebasing ensteht allerdings ein sauberer Verlauf. Bei genauerer Betrachtung der Historie entpuppt sich der Rebased-Branch als linearer Verlauf – es scheint als sei die ganze Arbeit in einer Serie entstanden, auch wenn sie in Wirklichkeit parallel stattfand. +Nun ist der Schnappschuss, auf den C3' zeigt, exakt der gleiche, wie der auf den C5 in dem Merge-Beispiel gezeigt hat. Bei dieser Zusammenführung entsteht kein unterschiedliches Produkt, durch Rebasing ensteht allerdings ein sauberer Verlauf. Bei genauerer Betrachtung der Historie entpuppt sich der Rebased-Branch als linearer Verlauf – es scheint, als sei die ganze Arbeit in einer Serie entstanden, auch wenn sie in Wirklichkeit parallel stattfand. -Du wirst das häufig anwenden um sicherzustellen, dass sich Deine Commits sauber in einen Remote-Branch integrieren – möglicherweise in einem Projekt bei dem Du Dich beteiligen möchtest, Du jedoch nicht der Verantwortliche bist. In diesem Fall würdest Du Deine Arbeiten in einem eigenen Branch erledigen und im Anschluss Deine Änderungen auf `origin/master` rebasen. Dann hätte der Verantwortliche nämliche keinen Aufwand mit der Integration – nur einen Fast-Forward oder eine saubere Integration (= Rebase?). +Du wirst das häufig anwenden um sicherzustellen, dass sich Deine Commits sauber in einen Remote-Branch integrieren – möglicherweise in einem Projekt, bei dem Du Dich beteiligen möchtest, Du jedoch nicht der Verantwortliche bist. In diesem Fall würdest Du Deine Arbeiten in einem eigenen Branch erledigen und im Anschluss Deine Änderungen auf `origin/master` rebasen. Dann hätte der Verantwortliche nämlich keinen Aufwand mit der Integration – nur einen Fast-Forward oder eine saubere Integration (= Rebase?). -Beachte, dass der Schnappschuss nach dem letzten Commit, ob es der letzte der Rebase-Commits nach einem Rebase oder der finale Merge-Commit nach einem Merge ist, exakt gleich ist. Sie unterscheiden sich nur in ihrem Verlauf. Rebasing wiederholt einfach die Änderungen einer Arbeitslinie auf einer anderen, in der Reihenfolge in der sie entstanden sind. Im Gegensatz hierzu nimmt Merging die beiden Endpunkte der Arbeitslinien und führt diese zusammen. +Beachte, dass der Schnappschuss, welche auf den letzten Commit zeigt, ob es nun der letzte der Rebase-Commits nach einem Rebase oder der finale Merge-Commit nach einem Merge ist, der selbe Schnappschuss ist, nur der Verlauf ist ein anderer. Rebasing wiederholt einfach die Änderungen einer Arbeitslinie auf einer anderen in der Reihenfolge, in der sie entstanden sind. Im Gegensatz hierzu nimmt Merging die beiden Endpunkte der Arbeitslinien und führt diese zusammen. ### Mehr interessante Rebases ### -Du kannst Deinen Rebase auch auf einem anderen Branch als dem Rebase-Branch anwenden lassen. Nimm zum Beispiel den Verlauf in Abbildung 3-31. Du hattest einen Themen-Branch (`server`) eröffnet um ein paar serverseitige Funktionalitäten zu Deinem Projekt hinzuzufügen und einen Commit gemacht. Dann hast Du einen weiteren Branch abgezweigt um clientseitige Änderungen (`client`) vorzunehmen und dort ein paarmal committed. Zum Schluss hast Du wieder zu Deinem Server-Branch gewechselt und ein paar weitere Commits gebaut. +Du kannst Deinen Rebase auch auf einem anderen Branch als dem Rebase-Branch anwenden lassen. Nimm zum Beispiel den Verlauf in Abbildung 3-31. Du hattest einen Themen-Branch (`server`) angelegt, um ein paar serverseitige Funktionalitäten zu Deinem Projekt hinzuzufügen, und hast dann einen Commit gemacht. Dann hast Du einen weiteren Branch abgezweigt, um clientseitige Änderungen (`client`) vorzunehmen und dort ein paarmal committed. Zum Schluss hast Du wieder zu Deinem Server-Branch gewechselt und ein paar weitere Commits gebaut. @@ -828,13 +834,13 @@ Abbildung 3-31. Ein Verlauf mit einem Themen-Branch basierend auf einem weiteren -Stell Dir vor, Du entscheidest Dich Deine clientseitigen Änderungen für einen Release in die Hauptlinie zu mergen, die serverseitigen Änderungen möchtest Du aber noch zurückhalten bis sie besser getestet wurden. Du kannst einfach die Änderungen am Client, die den Server nicht betreffen, (C8 und C9) mit der `--onto`-Option von `git rebase` erneut auf den Master-Branch anwenden: +Angenommen, Du entscheidest Dich, Deine clientseitigen Änderungen für einen Release in die Hauptlinie zu mergen, während Du die serverseitigen Änderungen noch zurückhalten möchtest, bis sie besser getestet wurden. Du kannst einfach die Änderungen am Client, die den Server nicht betreffen, (C8 und C9) mit der `--onto`-Option von `git rebase` erneut auf den Master-Branch anwenden: $ git rebase --onto master server client -Das bedeutet einfach “Checke den Client-Branch aus, finde die Patches heraus die auf dem gemeinsamen Vorfahr der `client`- und `server`-Branches basieren und wende sie erneut auf dem `master`-Branch an.” Das ist ein bisschen komplex, aber das Ergebnis – wie in Abbildung 3-32 – ist richtig cool. +Das bedeutet einfach, “Checke den Client-Branch aus, finde die Patches heraus, die auf dem gemeinsamen Vorfahr der `client`- und `server`-Branches basieren und wende sie erneut auf dem `master`-Branch an.” Das ist ein bisschen komplex, aber das Ergebnis – wie in Abbildung 3-32 – ist richtig cool. @@ -855,13 +861,13 @@ Abbildung 3-33. Fast-forwarding Deines Master-Branches um die Client-Branch-Änd -Lass uns annehmen, Du entscheidest Dich Deinen Server-Branch ebenfalls einzupflegen. Du kannst den Server-Branch auf den Master-Branch rebasen ohne diesen vorher auschecken zu müssen, indem Du das Kommando `git rebase [Basis-Branch] [Themen-Branch]` ausführst. Es macht für Dich den Checkout des Themen-Branches (in diesem Fall `server`) und wiederholt ihn auf dem Basis-Branch (`master`): +Lass uns annehmen, Du entscheidest Dich, Deinen Server-Branch ebenfalls einzupflegen. Du kannst den Server-Branch auf den Master-Branch rebasen, ohne diesen vorher auschecken zu müssen, indem Du die Anweisung `git rebase [Basis-Branch] [Themen-Branch]` ausführst. Sie macht für Dich den Checkout des Themen-Branches (in diesem Fall `server`) und wiederholt ihn auf dem Basis-Branch (`master`): $ git rebase master server -Das wiederholt Deine `server`-Arbeit auf der Basis der `server`-Arbeit, wie in Abbildung 3-34 ersichtlich. +Das wiederholt Deine `server`-Arbeit auf der Basis der `master`-Arbeit, wie in Abbildung 3-34 ersichtlich. @@ -877,7 +883,7 @@ Dann kannst Du den Basis-Branch (`master`) fast-forwarden: -Du kannst den `client`- und `server`-Branch nun entfernen, da Du die ganze Arbeit bereits integriert wurde und Sie nicht mehr benötigst. Du hinterlässt den Verlauf für den ganzen Prozess wie in Abbildung 3-35: +Du kannst den `client`- und `server`-Branch nun entfernen, da Du die ganze Arbeit bereits integriert wurde und sie nicht mehr benötigst. Du hinterlässt den Verlauf für den ganzen Prozess wie in Abbildung 3-35: $ git branch -d client $ git branch -d server @@ -900,20 +906,20 @@ Ahh, aber der ganze Spaß mit dem Rebasing kommt nicht ohne seine Schattenseiten -Wenn Du diesem Ratschlag folgst ist alles in Ordnung. Falls nicht, werden die Leute Dich hassen und Du wirst von Deinen Freunden und Deiner Familie verachtet. +Wenn Du diesem Ratschlag folgst, ist alles in Ordnung. Falls nicht, werden die Leute Dich hassen und Du wirst von Deinen Freunden und Deiner Familie verachtet. -Wenn Du Zeug rebased, hebst Du bestehende Commits auf und erstellst stattdessen welche, die zwar ähnlich aber unterschiedlich sind. Wenn Du Commits irgendwohin hochlädst und andere ziehen sich diese herunter und nehmen sie als Grundlage für ihre Arbeit, dann müssen Deine Mitwirkenden ihre Arbeit jedesmal re-mergen, sobald Du Deine Commits mit einem `git rebase` überschreibst und verteilst. Und richtig chaotisch wird's wenn Du versuchst deren Arbeit in Deine Commits zu integrieren. +Wenn Du Zeug rebased, hebst Du bestehende Commits auf und erstellst stattdessen welche, die zwar ähnlich aber unterschiedlich sind. Wenn Du Commits irgendwohin hochlädst und andere ziehen sich diese herunter und nehmen sie als Grundlage für ihre Arbeit, dann müssen Deine Mitwirkenden ihre Arbeit jedesmal re-mergen, sobald Du Deine Commits mit einem `git rebase` überschreibst und verteilst. Und richtig chaotisch wird es, wenn Du versuchst, deren Arbeit in Deine Commits zu integrieren. -Lass uns mal ein Beispiel betrachten wie das Rebasen veröffentlichter Arbeit Probleme verursachen kann. Angenommen Du klonst von einem zentralen Server und werkelst ein bisschen daran rum. Dein Commit-Verlauf sieht wie in Abbildung 3-36 aus. +Lass uns mal ein Beispiel betrachten, wie das Rebasen veröffentlichter Arbeit Probleme verursachen kann. Angenommen, Du klonst von einem zentralen Server und werkelst ein bisschen daran rum. Dein Commit-Verlauf sieht wie in Abbildung 3-36 aus. Insert 18333fig0336.png -Abbildung 3-36. Klon ein Repository und baue etwas darauf auf. +Abbildung 3-36. Klone ein Repository und baue etwas darauf auf. @@ -926,12 +932,12 @@ Abbildung 3-37. Fetche mehrere Commits und merge sie in Deine Arbeit. -Als nächstes entscheidet sich die Person, welche den Merge hochgeladen hat diesen rückgängig zu machen und stattdessen die Commits zu rebasen. Sie macht einen `git push --force` um den Verlauf auf dem Server zu überschreiben. Du lädst Dir das Ganze dann mit den neuen Commits herunter. +Als nächstes entscheidet sich die Person, welche den Merge hochgeladen hat, diesen rückgängig zu machen und stattdessen die Commits zu rebasen. Sie macht einen `git push --force`, um den Verlauf auf dem Server zu überschreiben. Du lädst Dir das Ganze dann mit den neuen Commits herunter. Insert 18333fig0338.png -Abbildung 3-38. Jemand pusht rebased Commits und verwirft damit Commitd auf denen Deine Arbeit basiert. +Abbildung 3-38. Jemand pusht rebased Commits und verwirft damit Commits, auf denen Deine Arbeit basiert. @@ -944,15 +950,15 @@ Abbildung 3-39. Du mergst die gleiche Arbeit nochmals in einen neuen Merge-Commi -Irgendwann musst Du seine Arbeit einmergen, damit Du auch zukünftig mit dem anderen Entwickler zusammenarbeiten kannst. Danach wird Dein Commit-Verlauf sowohl den C4 als auch den C4'-Commit enthalten, weche zwar verschiedene SHA-1-Hashes besitzen aber die gleichen Änderungen und die gleiche Commit-Beschreibung enthalten. Wenn Du so einen Verlauf mit `git log` betrachtest, wirst Du immer zwei Commits des gleichen Autors, zur gleichen Zeit und mit der gleichen Commit-Nachricht sehen. Was ganz schön verwirrend ist. Wenn Du diesen Verlauf außerdem auf den Server hochlädst, wirst Du dort alle rebasierten Commits einführen, was auch noch andere verwirren kann. +Irgendwann musst Du seine Arbeit mergen, damit Du auch zukünftig mit dem anderen Entwickler zusammenarbeiten kannst. Danach wird Dein Commit-Verlauf sowohl den C4 als auch den C4'-Commit enthalten, welche zwar verschiedene SHA-1-Hashes besitzen, aber die gleichen Änderungen und die gleiche Commit-Beschreibung enthalten. Wenn Du so einen Verlauf mit `git log` betrachtest, wirst Du immer zwei Commits des gleichen Autors, zur gleichen Zeit und mit der gleichen Commit-Nachricht sehen. Was ganz schön verwirrend sein wird. Wenn Du diesen Verlauf außerdem auf den Server hochlädst, wirst Du dort alle rebasierten Commits nochmals einführen, was die Leute noch mehr verwirren kann. -Wenn Du rebasing als Weg behandelst um aufzuräumen und mit Commits zu arbeiten, bevor Du sie hochlädst und wenn Du nur Commits rebased, die noch nie publiziert wurden, dann fährst Du goldrichtig. Wenn Du Commits rebased die bereits veröffentlicht wurden und Leute vielleicht schon ihre Arbeit darauf aufgebaut haben, dann bist Du vielleicht für frustrierenden Ärger verantwortlich. +Wenn Du rebasing als einen Weg getrachtest, um aufzuräumen und mit Commits zu arbeiten, bevor Du sie hochlädst und wenn Du rebase nur auf Commits anwendest, die noch nie öffentlich zugänglich waren, dann fährst Du goldrichtig. Wenn Du rebase auf Commits anwendest, die bereits veröffentlicht wurden und Leute vielleicht schon ihre Arbeit darauf aufgebaut haben, dann kannst Du Dich auf frustrierenden Ärger gefasst machen. ## Zusammenfassung ## -Wir haben einfaches Branching und Merging mit Git behandelt. Du solltest nun gut damit zurecht kommen Branches zu erstellen, zwischen Branches zu wechseln und lokale Branches mit einem Merge zusammenzuführen. Ausserdem solltest Du in der Lage sein Deine Branches zu veröffentlichen indem Du sie auf einen zentralen Server lädst, mit anderen auf öffentlichen Branches zusammenzuarbeiten und Deine Branches zu rebasen bevor sie veröffentlicht werden. +Wir haben einfaches Branching und Merging mit Git behandelt. Du solltest nun gut damit zurecht kommen, Branches zu erstellen, zwischen Branches zu wechseln und lokale Branches mit einem Merge zusammenzuführen. Außerdem solltest Du in der Lage sein, Deine Branches zu veröffentlichen, indem Du sie auf einen zentralen Server lädst, mit anderen auf öffentlichen Branches zusammenzuarbeiten und Deine Branches zu rebasen, bevor sie veröffentlicht werden. diff --git a/de/04-git-server/01-chapter4.markdown b/de/04-git-server/01-chapter4.markdown index d78f410e4..2bdb6f996 100644 --- a/de/04-git-server/01-chapter4.markdown +++ b/de/04-git-server/01-chapter4.markdown @@ -47,9 +47,9 @@ Oder Du kannst das machen: $ git clone file:///opt/git/project.git - + -Git arbeitet etwas anders, wenn Du am Anfang der URL ausdrücklich `file://` angibst. Wenn Du nur den Pfad angibst, versucht Git harte Links zu benutzen oder Git kopiert direkt die benötigten Dateien. Wenn Du `file://` angibst, startet Git den Prozess, den es normalerweise zum Übertragen von Daten über ein Netzwerk verwendet, dass ist gewöhnlich eine wesentlich ineffizientere Methode zum Übertragen der Daten. Der Hauptgrund das `file://`-Präfix anzugeben ist eine saubere Kopie von dem Repository mit fremden Referenzen oder fehlenden Objekten – generell nach einem Import von einem anderen Versionskontrollsystem oder etwas ähnliches (siehe Kapitel 9 für Wartungsarbeiten). Wir benutzen hier den normalen Pfad, weil das fast immer schneller ist. +Git arbeitet etwas anders, wenn Du am Anfang der URL ausdrücklich `file://` angibst. Wenn Du nur den Pfad angibst, und sowohl die Quelle, als auch das Ziel sich auf dem selben Dateisystem befinden, versucht Git harte Links zu benutzen. Wenn sie sich nicht auf dem selben Dateisystem befinden, kopiert Git die benötigten Objekte mit Hilfe der Standardkopierfunktion des jeweiligen Betriebssystems. Wenn Du `file://` angibst, startet Git den Prozess, den es normalerweise zum Übertragen von Daten über ein Netzwerk verwendet, dass ist gewöhnlich eine wesentlich ineffizientere Methode zum Übertragen der Daten. Der Hauptgrund das `file://`-Präfix anzugeben ist eine saubere Kopie von dem Repository mit fremden Referenzen oder fehlenden Objekten – generell nach einem Import von einem anderen Versionskontrollsystem oder etwas ähnliches (siehe Kapitel 9 für Wartungsarbeiten). Wir benutzen hier den normalen Pfad, weil das fast immer schneller ist. @@ -123,9 +123,9 @@ Die negative Seite von SSH ist, dass Du Deine Repositories nicht anonym darüber ### Das Git Protokoll ### - + -Als nächstes kommt das Git Protokoll. Das ist ein spezieller Dämon, der zusammen mit Git kommt. Er horcht auf einem bestimmten Port (9418), dieser Service ist vergleichbar mit dem SSH-Protokoll, aber ohne jegliche Authentifizierung. Um ein Repository über das Git Protokoll, musst Du die `gitk-export-daemon-ok` Datei erstellen – der Dämon bietet kein Repository ohne die Datei darin an – außer dieser Datei gibt es keine Sicherheit. Entweder das Git Repository ist für jeden zum Clonen verfügbar oder halt nicht. Das bedeutet, dass dieses Protokoll generell kein push anbietet. Du kannst push-Zugriff aktivieren; aber ohne Authentifizierung, wenn Du den push-Zugriff aktivierst, kann jeder im Internet, der Deine Projekt-URL findet, zu Deinem Projekt pushen. Ausreichend zu sagen, dass das selten ist. +Als nächstes kommt das Git Protokoll. Das ist ein spezieller Dämon, der zusammen mit Git kommt. Er horcht auf einem bestimmten Port (9418), dieser Service ist vergleichbar mit dem SSH-Protokoll, aber ohne jegliche Authentifizierung. Um ein Repository über das Git Protokoll, musst Du die `git-daemon-export-ok` Datei erstellen – der Dämon bietet kein Repository ohne die Datei darin an – außer dieser Datei gibt es keine Sicherheit. Entweder das Git Repository ist für jeden zum Clonen verfügbar oder halt nicht. Das bedeutet, dass dieses Protokoll generell kein push anbietet. Du kannst push-Zugriff aktivieren; aber ohne Authentifizierung, wenn Du den push-Zugriff aktivierst, kann jeder im Internet, der Deine Projekt-URL findet, zu Deinem Projekt pushen. Ausreichend zu sagen, dass das selten ist. #### Die Vorteile #### @@ -137,7 +137,8 @@ Das Git Protokoll ist das schnellste verfügbare Transfer Protokoll. Wenn Du vie #### Die Nachteile #### - + + Die Negativseite des Git Protokoll ist das Fehlen der Authentifizierung. Es ist generell unerwünscht, dass das Git Protokoll der einzige Zugang zu dem Projekt ist. Im Allgemeinen willst Du es mit SSH-Zugriff für die Entwickler paaren, die push (Schreib) Zugriff haben und jeder andere benutzt `git://` für Nur-Lese-Zugriff. Es ist vielleicht auch das das schwierigste Protokoll beim Einrichten. Es muss ein eigener Dämon laufen, welcher Git-spezifisch ist – wir wollen im „Gitosis“-Abschnitt in diesem Kapitel schauen, wie man einen einrichtet – es setzt eine `xinetd`-Konfiguration oder ähnliches voraus, das ist nicht immer ein Spaziergang. Es setzt auch einen Firewall-Zugriff auf den Port 9418 voraus, das ist kein Standard-Port, den Firmen-Firewalls immer erlauben. Hinter einer großen Firmen-Firewall ist dieser unklare Port häufig gesperrt. @@ -194,14 +195,15 @@ Die Unterseite vom Servieren von Deinem Repository über HTTP ist, dass es recht ## Git auf einen Server bekommen ## - + + Um zunächst einen beliebigen Git Server einzurichten, musst Du ein existierendes Repository in ein neues einfaches Repository exportieren – ein Repository, dass kein Arbeitsverzeichnis enthält. Das ist im Allgemeinen einfach zu erledigen. Um zunächst Dein Repository zu klonen, um ein neues einfaches Repository anzulegen, führst Du den Klonen-Befehl mit der `--bare` Option aus. Per Konvention haben einfache Repository Verzeichnisse die Endung `.git`, wie hier: $ git clone --bare my_project my_project.git - Initialized empty Git repository in /opt/projects/my_project.git/ + Cloning into bare repository 'my_project.git'... + done. @@ -285,8 +287,8 @@ Ein anderer Weg ist, einen LDAP-Server zur Authentifizierung zu benutzen oder ei ## Generiere Deinen öffentlichen SSH-Schlüssel ## - + + Darüber hinaus benutzen viele Git-Server öffentliche SSH-Schlüssel zur Authentifizierung. Um einen öffentlichen Schlüssel bereitzustellen muss jeder Benutzer Deines Systems einen solchen Schlüssel generieren, falls sie noch keinen haben. Dieser Prozess ist bei allen Betriebssystemen ähnlich. Als erstes solltest Du überprüfen, ob Du nicht schon einen Schlüssel hast. Standardmäßig werden die SSH-Schlüssel der Benutzer in ihrem `~/.ssh`-Verzeichnis gespeichert. Du kannst einfach überprüfen, ob Du einen Schlüssel hast, indem Du in das Verzeichnis gehst und den Inhalt auflistest: @@ -298,7 +300,7 @@ Als erstes solltest Du überprüfen, ob Du nicht schon einen Schlüssel hast. St -Du suchst nach Paar Dateien namens `irgendetwas` und `irgendetwas.pub`, die Datei `irgendetwas` heißt normalerweise `id_dsa` oder `id_rsa`. Die `.pub`-Datei ist Dein öffentlicher Schlüssel und die andere Datei ist Dein privater Schlüssel. Wenn Du diese Dateien nicht hast (oder gar kein `.ssh`-Verzeichnis hast), kannst Du sie mit dem Ausführen des Programms `ssh-keygen` erzeugen. Das Programm wird mit dem SSH-Paket auf Linux/Mac-Systemen mitgeliefert und kommt mit dem MSysGit-Paket unter Windows: +Du suchst nach einem Dateienpaar namens `irgendetwas` und `irgendetwas.pub`, die Datei `irgendetwas` heißt normalerweise `id_dsa` oder `id_rsa`. Die `.pub`-Datei ist Dein öffentlicher Schlüssel, und die andere Datei ist Dein privater Schlüssel. Wenn Du diese Dateien nicht hast (oder gar kein `.ssh`-Verzeichnis hast), kannst Du sie mit dem Ausführen des Programms `ssh-keygen` erzeugen. Das Programm wird mit dem SSH-Paket auf Linux/Mac-Systemen mitgeliefert und kommt mit dem MSysGit-Paket unter Windows: $ ssh-keygen Generating public/private rsa key pair. @@ -452,6 +454,13 @@ Welche Aufgabe hat der `post-update` Hook? Er enthält in etwa folgendes: $ cat .git/hooks/post-update #!/bin/sh + # + # An example hook script to prepare a packed repository for use over + # dumb transports. + # + # To enable this hook, rename this file to "post-update". + # + exec git-update-server-info @@ -569,7 +578,7 @@ Gitosis setzt einige Python Werkzeuge voraus. Deshalb solltest Du zuerst das Pyt Danach klonst Du Gitosis von der offiziellen Projektseite und installierst es: - $ git clone git://eagain.net/gitosis.git + $ git clone https://github.com/tv42/gitosis.git $ cd gitosis $ sudo python setup.py install @@ -617,7 +626,7 @@ Jetzt kann es losgehen. Wenn Du alles richtig eingerichtet hast, kannst Du jetzt $ ssh git@gitserver PTY allocation request failed on channel 0 - fatal: unrecognized command 'gitosis-serve schacon@quaternion' + ERROR:gitosis.serve.main:Need SSH_ORIGINAL_COMMAND in environment. Connection to gitserver closed. @@ -649,8 +658,8 @@ Wenn Du Dir die Datei `gitosis.conf` anschaust, sollten lediglich Daten für das [gitosis] [group gitosis-admin] - writable = gitosis-admin members = scott + writable = gitosis-admin @@ -661,22 +670,22 @@ In dieser Datei wird Dir angezeigt, dass nur der Benutzer ‚scott‘ — das is Lass uns jetzt für Dich ein neues Projekt hinzufügen. Dazu fügen wir eine neue Sektion mit dem Namen `mobile` hinzu, in der wir alle Teammitglieder aus dem „Mobile“-Team und alle Repositorys, die von Ihnen benötigt werden, auflisten. Da ‚scott‘ bisher der einzige Benutzer im System ist, werden wir ihn als einziges Teammitglied hinzufügen. Das erste von uns erzeugte Projekt mit dem wir anfangen, nennt sich `iphone_project`: [group mobile] - writable = iphone_project members = scott + writable = iphone_project Immer wenn Du Änderungen im Projekt `gitosis-admin` durchführst, musst Du diese Änderungen auch einchecken und auf den Server pushen, damit diese auch eine Wirkung zeigen: $ git commit -am 'add iphone_project and mobile group' - [master]: created 8962da8: "changed name" - 1 files changed, 4 insertions(+), 0 deletions(-) - $ git push + [master 8962da8] add iphone_project and mobile group + 1 file changed, 4 insertions(+) + $ git push origin master Counting objects: 5, done. - Compressing objects: 100% (2/2), done. - Writing objects: 100% (3/3), 272 bytes, done. - Total 3 (delta 1), reused 0 (delta 0) - To git@gitserver:/opt/git/gitosis-admin.git + Compressing objects: 100% (3/3), done. + Writing objects: 100% (3/3), 272 bytes | 0 bytes/s, done. + Total 3 (delta 0), reused 0 (delta 0) + To git@gitserver:gitosis-admin.git fb27aec..8962da8 master -> master @@ -687,7 +696,7 @@ Du kannst Deinen ersten Push für das neue Projekt `iphone_project` ausführen, $ git push origin master Initialized empty Git repository in /opt/git/iphone_project.git/ Counting objects: 3, done. - Writing objects: 100% (3/3), 230 bytes, done. + Writing objects: 100% (3/3), 230 bytes | 0 bytes/s, done. Total 3 (delta 0), reused 0 (delta 0) To git@gitserver:iphone_project.git * [new branch] master -> master @@ -709,8 +718,8 @@ Da Du an diesem Projekt nicht alleine, sondern mit Deinen Freunden, arbeiten wil Damit diese Personen Lese- und Schreibzugriff auf das Projekt `iphone_project` haben, musst Du sie dem ‚mobile‘-Team hinzufügen: [group mobile] - writable = iphone_project members = scott john josie jessica + writable = iphone_project @@ -721,12 +730,12 @@ Nachdem Du diese Änderung commitet und gepusht hast, können alle vier Benutzer Mit Gitosis kann man auch einfache Zugriffsberechtigungen setzen. Wenn John nur Lesezugriff zum Projekt haben soll, dann kannst Du stattdessen folgendes angeben: [group mobile] - writable = iphone_project members = scott josie jessica + writable = iphone_project [group mobile_ro] - readonly = iphone_project members = john + readonly = iphone_project @@ -736,12 +745,12 @@ Mit dieser Konfiguration kann John das Projekt klonen und kann neue Stände heru members = scott josie jessica [group mobile] - writable = iphone_project members = @mobile_committers + writable = iphone_project [group mobile_2] - writable = another_iphone_project members = @mobile_committers john + writable = another_iphone_project @@ -878,9 +887,9 @@ Diese Regel gehört dann zum Regelsatz des `gitolite` Repository. An dieser Stelle fragst Du Dich vielleicht, wie die Zugriffsregeln eigentlich angewandt werden. Lass uns das kurz anschauen. - + -Es gibt zwei Ebenen für die Zugriffsberechtigung in Gitolite. Die erste befindet sich auf Repository Ebene. Wenn Du Lese- oder Schreifzugriff auf jede Ref in einem Repository hast, dann kannst Du damit das ganze Repository sowohl lesen, als auch schreiben. Gitosis kennt nur diese Art der Zugriffsberechtigung. +Es gibt zwei Ebenen für die Zugriffsberechtigung in Gitolite. Die erste befindet sich auf Repository Ebene. Wenn Du Lese- oder Schreifzugriff auf jede Ref in einem Repository hast, dann kannst Du damit das ganze Repository sowohl lesen, als auch schreiben. @@ -1112,9 +1121,9 @@ Wenn ein Anwender ein geschützes, nicht öffentliches Repository auf GitHub ver ## Einrichten eines Benutzeraccounts ### - + -Um loslegen zu können, musst Du Dir einen Benutzeraccount erstellen. Gib dazu die Adresse `http://github.com/plans` in Deinem Browser ein und wähle den Button „Sign Up“ unter dem „Free account“-Bereich aus (siehe Abbildung 4-2). Danach wirst Du auf die Anmeldeseite weitergeleitet. +Um loslegen zu können, musst Du Dir einen Benutzeraccount erstellen. Gib dazu die Adresse `https://github.com/pricing` in Deinem Browser ein und wähle den Button „Sign Up“ unter dem „Free account“-Bereich aus (siehe Abbildung 4-2). Danach wirst Du auf die Anmeldeseite weitergeleitet. @@ -1130,8 +1139,8 @@ Auf dieser Seite musst Du einen Nutzernamen auswählen, der bisher im System nic Insert 18333fig0403.png Abbildung 4-3. Das Formular für die GitHub Benutzerregistrierung. - + + Wenn Du Deinen öffentlichen SSH Schlüssel zur Hand hast, kannst Du diesen auch gleich bei der Registrierung angeben. Die Vorgehensweise zum Generieren eines Schlüssels haben wir bereits im Kapitel 4.3 besprochen. Du musst den Inhalt der öffentlichen Schlüsseldatei kopieren und in das „SSH Public Key“ Formularfeld einfügen. Wenn Du auf den „explain ssh keys“ Link klickst, erhälst Du detailierte Anweisungen zum Ausführen dieses Vorgangs auf verschiedenen Betriebssystemen. Wenn Du auf den „I agree, sign me up“ Button drückst, landest Du in Deinem neuen Benutzer-Dashboard (siehe Abbildung 4-4). diff --git a/de/05-distributed-git/01-chapter5.markdown b/de/05-distributed-git/01-chapter5.markdown index 404a05c4f..d7d2ca314 100644 --- a/de/05-distributed-git/01-chapter5.markdown +++ b/de/05-distributed-git/01-chapter5.markdown @@ -32,8 +32,8 @@ Bild 5-1. Zentralisierter Workflow Das heißt: wenn zwei Entwickler Code aus dem zentralen Repository abholen und beide Änderungen vornehmen, dann kann der erste Entwickler seine Änderungen ohne Probleme im zentralen Repository abliefern. Der zweite Entwickler muss sie zunächst mit den Änderungen des ersten Entwicklers zusammenführen, damit er dessen Arbeit nicht überschreibt. Dieses Konzept trifft sowohl auf Git als auch auf Subversion (und jedes andere CVCS) zu, und es funktioniert in Git perfekt. - + + In einem kleinen Team oder einem Team, das mit einem zentralisierten Workflow zufrieden ist, kann man diesen Workflow ohne weiteres mit Git realisieren. Man setzt einfach ein einziges Repository auf und gibt jedem im Team Schreibzugriff („push access“). Git sorgt dann dafür, dass niemand die Arbeit von anderen überschreiben kann. Wenn ein Entwickler das Repository klont, Änderungen vornimmt und dann versucht ins zentrale Repository zu pushen, obwohl jemand anders in der Zwischenzeit Änderungen gepusht hat, dann wird der Server das zurückweisen. Dem Entwickler wird dann mitgeteilt, dass er versucht hat, sogeannte „non-fast-forward“ Änderungen hochzuladen und dass er zuvor die Änderungen des anderen Entwicklers herunterladen und mit seinen zusammenführen muss. Viele Leute mögen diesen Arbeitsablauf, weil sie mit dem Paradigma bereits vertraut sind und sich damit wohl fühlen. @@ -45,12 +45,12 @@ In einem kleinen Team oder einem Team, das mit einem zentralisierten Workflow zu Weil Git ermöglicht, eine Vielzahl von externen Repositories zu betreiben, ist es außerdem möglich, einen Arbeitsprozess zu gestalten, in dem jeder Entwickler Schreibzugriff auf sein eigenes öffentliches Repository hat, aber nur Lesezugriff auf die Repositories von allen anderen Beteiligten. In diesem Szenario stellt jedes Repository ein eigenes „offizielles“ Projekt dar. Um zu einem solchen distribuierten Projekt Änderungen beizusteuern, kannst Du einen eigenen, öffentlichen Klon des Projektes anlegen und Deine Änderungen dort publizieren. Anschließend kannst Du den Betreiber des Haupt-Repositories bitten, Deine Änderungen in sein Repository zu übernehmen. Er kann dann Dein Repository als ein externes Repository auf seinem Rechner einrichten, Deine Änderungen lokal testen, sie in einen seiner Branches (z.B. master) mergen und dann in sein öffentliches Repository pushen. Dieser Prozess läuft wie folgt ab (siehe Bild 5-2): - + + + + + + 1. Der Projekt Betreiber pusht in ein öffentliches Repository. 2. Ein Mitarbeiter klont das Repository und nimmt Änderungen daran vor. @@ -75,10 +75,10 @@ Dies ist ein weit verbreiteter Arbeitsablauf wie ihn z.B. auch GitHub ermöglich Dies ist Variante eines Workflows mit zahlreichen Repositories, die normalerweise von sehr großen Projekten mit hunderten von Mitarbeitern verwendet wird. Das bekannteste Beispiel ist wahrscheinlich der Linux Kernel. In diesem Projekt sind zahlreiche Integration Manager, die „Leutnants“, für verschiedene Bereiche des Repositories zuständig. Für sämtliche Leutnants gibt es wiederum einen Integration Manager, der als der „wohlwollende Diktator“ („benevolent dictator“) bezeichnet wird. Das Repository des wohlwollenden Diktators fungiert als das Referenz-Repository aus dem alle Beteiligten ihre eigenen Repositories aktualisieren müssen. Dieser Prozess funktioniert also wie folgt (siehe Bild 5-3) - + + + + 1. Normale Entwickler arbeiten in ihren Arbeitsbranches (xxx) und rebasen (xxx) ihre Änderungen auf der Basis des Master Branches. Der Master Branch ist derjenige des Diktators. 2. Die Leutnants mergen die Arbeitsbranches der Entwickler in ihre Master Branches. @@ -152,8 +152,8 @@ Wenn Du diesen Befehl ausführst, bevor Du einen Commit anlegst, warnt er dich, Versuche außerdem, Deine Änderungen in logisch zusammenhängende Einheiten zu gruppieren. Wenn möglich, versuche Commits möglichst leichtverständlich (xxx) zu gestalten: arbeite nicht ein ganzes Wochenende lang an fünf verschiedenen Problemen und committe sie dann am Montag als einen einzigen, riesigen Commit. Selbst wenn Du am Wochenende keine Commits angelegt hast, verwende die Staging Area, um Deine Änderungen auf mehrere Commits aufzuteilen, jeweils mit einer verständlichen Meldung. Wenn einige Änderungen dieselbe Datei betreffen, probiere sie mit `git add --patch` nur teilweise zur Staging Area hinzuzufügen (das werden wir in Kapitel 6 noch im Detail besprechen). Der Projekt Snapshot wird am Ende derselbe sein, ob Du nun einen einzigen großen oder mehrere kleine Commits anlegst, daher versuche, es anderen Entwickler zu erleichtern machen, Deine Änderungen zu verstehen. Auf diese Weise machst Du es auch einfacher, einzelne Änderungen später herauszunehmen oder rückgängig zu machen. Kapitel 6 beschreibt eine Reihe nützlicher Git Tricks, die hilfreich sind, um die Historie umzuschreiben oder interaktiv Dateien zur Staging Area hinzuzufügen. Verwende diese Hilfsmittel, um eine sauber und leicht verständliche Historie von Änderungen aufzubauen. - + + Ein weitere Sache, der Du ein bisschen Aufmerksamkeit schenken solltest, ist die Commit Meldung selbst. Wenn man sich angewöhnt, aussagekräftige und hochwertige Commit Meldungen zu schreiben, macht man sich selbst und anderen das Leben erheblich einfacher. Im allgemeinen sollte eine Commit Meldung mit einer einzelnen Zeile anfangen, die nicht länger als 50 Zeichen sein sollte. Dann sollte eine leere Zeile folgen und schließlich eine ausführlichere Beschreibung der Änderungen. @@ -188,8 +188,8 @@ In den folgenden Beispielen hier und fast überall in diesem Buch verwende ich k Das einfachste Setup, mit dem Du zu tun haben wirst, ist ein privates Projekt mit ein oder zwei Entwicklern. Mit „privat“ meine ich, dass es „closed source“, d.h. nicht lesbar für Dritte ist. Alle beteiligten Entwickler haben Schreibzugriff auf das Repository. - + + In einer solchen Umgebung kann man einen ähnlichen Workflow verwenden, wie für Subversion oder ein anderes zentralisiertes System. Du hast dann immer noch Vorteile wie, dass Du offline committen kannst und dass Branching und Merging so unglaublich einfach ist. Der Hauptunterschied ist, dass Merges auf der Client Seite stattfinden und nicht, wenn man committet, auf dem Server. Schauen wir uns an, wie die Arbeit von zwei Entwicklern in einem gemeinsamen Repository abläuft. Der erste Entwickler, John, klont das Repository, nimmt eine Änderung vor und comittet auf seinem Rechner. (Wir kürzen die Beispiele etwas ab und ersetzen die hierfür irrelevanten Protokoll Meldungen mit `xxx`.) @@ -330,7 +330,7 @@ Jessica hat die Arbeit in ihrem Topic Branch abgeschlossen, aber sie will wissen removed invalid default value - + Jetzt kann Jessica zunächst ihren Topic Branch `issue54` in ihren `master` Branch mergen, dann Johns Änderungen aus `origin/master` in ihren `master` Branch mergen und schließlich das Resultat auf den `origin` Server pushen. Als erstes wechselt sie zurück auf ihren `master` Branch: @@ -386,7 +386,7 @@ Beide Entwickler haben jetzt einige Male committed und die Arbeit des jeweils an Insert 18333fig0510.png Bild 5-10. Jessicas Historie nachdem sie sämtliche Änderungen auf den Server gepusht hat - + Dies ist eine der simpelsten Workflow Varianten. Du arbeitest eine Weile, normalerweise in einem Topic Branch, und mergst in Deinen `master` Branch, wenn Du fertig bist. Wenn Du Deine Änderungen anderen zur Verfügung stellen willst, holst Du den aktuellen `origin/master` Branch, mergst Deinen `master` Branch damit und pushst das ganze zurück auf den `origin` Server. Der Ablauf sieht in etwa wie folgt aus (Bild 5-11). @@ -765,10 +765,35 @@ Zunächst musst Du die IMAP Sektion in Deiner `~/.gitconfig` Datei ausfüllen. D port = 993 sslverify = false - + + -Wenn Dein IMAP Server kein SSL verwendet, kannst Du die letzten beiden Zeilen wahrscheinlich weglassen und der `host` dürfte mit `imap://` und nicht `imaps://` beginnen. Wenn Du diese Einstellungen konfiguriert hast, kannst Du `git send-email` verwenden, um Deine Patches in den Entwurfsordner des angegebenen IMAP Servers zu kopieren: +Wenn Dein IMAP Server kein SSL verwendet, kannst Du die letzten beiden Zeilen wahrscheinlich weglassen und der `host` dürfte mit `imap://` und nicht `imaps://` beginnen. Wenn Du diese Einstellungen konfiguriert hast, kannst Du `git imap-send` verwenden, um Deine Patches in den Entwurfsordner des angegebenen IMAP Servers zu kopieren: + + $ cat *.patch |git imap-send + Resolving imap.gmail.com... ok + Connecting to [74.125.142.109]:993... ok + Logging in... + sending 2 messages + 100% (2/2) done + + + +Jetzt kannst Du in Deinen Entwürfe-Ordner wechseln, die Mailingliste an die Du den Patch senden möchtest im An-Feld setzen, vielleicht noch den Maintainer oder die verantwortliche Person in das CC-Feld einfügen und dann das Ganze losschicken. + + + +Man kann Patches auch über einen SMTP-Server schicken. Wie im letzen Beispiel, kann man auch hier jeden einzelnen Wert mit einer Reihe von `git config` Kommandos setzen. Oder aber Du änderst die Sektion sendemail in Deiner `~/.gitconfig` Datei manuell: + + [sendemail] + smtpencryption = tls + smtpserver = smtp.gmail.com + smtpuser = user@gmail.com + smtpserverport = 587 + + + +Nach der Änderungen kannst Du mit `git send-email` die Patches abschicken: $ git send-email *.patch 0001-added-limit-to-log-function.patch @@ -818,8 +843,8 @@ Neben dem Wissen, das Du brauchst, um zu einem bestehenden Projekt Änderungen b ### In Topic Branches arbeiten ### - + + Wenn Du Änderungen von anderen übernehmen willst, ist normalerweise eine gute Idee, sie in einem Topic Branch auszuprobieren – d.h., einem temporären Branch, dessen Zweck nur darin besteht, die jeweiligen Änderungen auszuprobieren. Auf diese Weise ist es einfach, Patches ggf. anzupassen oder sie im Zweifelsfall im Topic Branch liegen zu lassen, wenn sie nicht funktionieren und Du im Moment nicht die Zeit hast, Dich weiter damit zu befassen. Es ist empfehlenswert, Topic Branches Namen zu geben, die gut kommunizieren, worum es sich bei den jeweiligen Änderungen dreht, wie z.B. `ruby_client` oder etwas ähnlich aussagekräftiges, das Dir hilft, Dich daran zu erinnern. Der Projekt Betreiber des Git Projektes selbst vergibt Namensräume für solche Branches – wie z.B. `sc/ruby_client`, wobei `sc` ein Kürzel für den jeweiligen Autor des Patches ist. Wie Du inzwischen weißt, kannst Du einen neuen Branch, der auf dem gegenwärtigen `master` Branch basiert, wie folgt erzeugen (xxx falsch, das stimmt nur, wenn `master` der aktuelle Branch ist xxx): @@ -1117,8 +1142,8 @@ Bild 5-22. Nach dem Topic Branch Merge Insert 18333fig0523.png Bild 5-23. Nach dem Topic Branch Release - + + Auf diese Weise kann jeder, der Dein Repository klont, auf einfache Weise Deinen aktuellen `master` Branch verwenden und ihn auf neue Releases aktualisieren. Oder er kann den `develop` Branch ausprobieren, in dem sich die jeweils letzten, brandneuen Änderungen befinden. Du kannst dieses Konzept noch weiterführen, indem Du einen `integrate` Branch pflegst, in den neue Änderungen jeweils integriert werden. Sobald der Code in diesem Branch stabil zu sein scheint und alle Tests durchlaufen (xxx), übernimmst Du die Änderungen in den `develop` Branch. Und wenn sie sich für eine Weile in der Praxis als stabil erwiesen haben, fast-forwardest (xxx) Du den `master` Branch. diff --git a/de/06-git-tools/01-chapter6.markdown b/de/06-git-tools/01-chapter6.markdown index 3f1726928..22435d8d2 100644 --- a/de/06-git-tools/01-chapter6.markdown +++ b/de/06-git-tools/01-chapter6.markdown @@ -3,36 +3,36 @@ -Bis hierher hast Du die meisten täglichen Kommandos und Arbeitsweisen gelernt, die Du brauchst um ein Git Repository für Deine Quellcode Kontrolle, zu benutzen. Du hast die grundlegenden Aufgaben des tracking und committing von Dateien gemeistert und Du hast von der Macht der staging area, des branching und des merging Gebrauch gemacht. +Bis hierher hast Du die meisten täglichen Kommandos und Arbeitsweisen gelernt, die Du brauchst um ein Git-Repository für Deine Quellcode-Kontrolle, zu benutzen. Du hast die grundlegenden Aufgaben des Nachverfolgens und Eincheckens von Dateien gemeistert und Du hast von der Macht der Staging-Area, des Branching und des Mergens Gebrauch gemacht. -Als nächstes werden wir einige sehr mächtige Werkzeuge besprechen, die Dir Git zur Verfügung stellt. Du wirst zwar nicht unbedingt jeden Tag verwenden, aber mit Sicherheit an einem bestimmten Punkt gute brauchen können. +Als Nächstes werden wir einige sehr mächtige Werkzeuge besprechen, die Dir Git zur Verfügung stellt. Du wirst zwar nicht unbedingt jeden Tag verwenden, aber mit Sicherheit an einem bestimmten Punkt gut brauchen können. ## Revision Auswahl ## -Git erlaubt dir, Commits auf verschiedenste Art und Weise auszuwählen. Diese sind nicht immer offensichtlich, aber es ist hilfreich diese zu kennen. +Git erlaubt Dir, Commits auf verschiedenste Art und Weise auszuwählen. Diese sind nicht immer offensichtlich, aber es ist hilfreich diese zu kennen. ### Einzelne Revisionen ### -Du kannst offensichtlich mithilfe des SHA-1 hash einen commit auswählen, aber es gibt auch Menschen freundlichere Methoden auf ein commit zu verweisen. Dieser Bereich skizziert die verschiedenen Wege, die man gehen kann um auf ein einzelnen commit zu referenzieren. +Du kannst offensichtlich mithilfe des SHA-1-Hashes einen Commit auswählen, aber es gibt auch menschenfreundlichere Methoden, auf einen Commit zu verweisen. Dieser Bereich skizziert die verschiedenen Wege, die man gehen kann, um sich auf ein einzelnen Commit zu beziehen. ### Abgekürztes SHA ### -Git ist intelligent genug, den richtigen commit herauszufinden, wenn man nur die ersten paar Zeichen angibt aber nur unter der Bedingung, dass der SHA-1 hash mindestens vier Zeichen lang und einzigartig ist — das bedeutet, dass es nur ein Objekt im derzeitigen Repository gibt, das mit diesem bestimmten SHA-1 hash beginnt. +Git ist intelligent genug, den richtigen Commit herauszufinden, wenn man nur die ersten paar Zeichen angibt, aber nur unter der Bedingung, dass der SHA-1-Hash mindestens vier Zeichen lang und einzigartig ist — das bedeutet, dass es nur ein Objekt im derzeitigen Repository gibt, das mit diesem bestimmten SHA-1-Hash beginnt. -Um zum Beispiel einen bestimmten commit zu sehen, kann man das `git log` Kommando ausführen und den commit identifizieren in dem man eine bestimmte Funktionalität hinzugefügt hat: +Um zum Beispiel einen bestimmten Commit zu sehen, kann man das `git log` Kommando ausführen und den Commit identifizieren, indem man eine bestimmte Funktionalität hinzugefügt hat: $ git log commit 734713bc047d87bf7eac9674765ae793478c50d3 @@ -56,7 +56,7 @@ Um zum Beispiel einen bestimmten commit zu sehen, kann man das `git log` Kommand -In diesem Fall wählt man `1c002dd....` wenn Du diesen commit mit `git show` anzeigen lassen willst, die folgenden Kommandos sind äquivalent (vorausgesetzt die verkürzte Version ist einzigartig): +In diesem Fall wählt man `1c002dd....`, wenn man diesen Commit mit `git show` anzeigen lassen will, die folgenden Kommandos sind äquivalent (vorausgesetzt die verkürzte Version ist einzigartig): $ git show 1c002dd4b536e7479fe34593e72e6c6c1819e53b $ git show 1c002dd4b536e7479f @@ -64,7 +64,7 @@ In diesem Fall wählt man `1c002dd....` wenn Du diesen commit mit `git show` anz -Git kann auch selber eine Kurzform für Deine einzigartigen SHA-1 Werte erzeugen. Wenn Du `--abbrev-commit` dem `git log` Kommando übergibst, wird es den kürzeren Wert benutzen diesen aber einzigartig halten; die Standardeinstellung sind sieben Zeichen aber es werden automatisch mehr benutzt wenn dies nötig ist um den SHA-1 hash eindeutig zu bezeichnen. +Git kann auch selber eine Kurzform für Deine einzigartigen SHA-1-Werte erzeugen. Wenn Du `--abbrev-commit` dem `git log` Kommando übergibst, wird es den kürzeren Wert benutzen, diesen aber einzigartig halten; die Standardeinstellung sind sieben Zeichen, aber es werden automatisch mehr benutzt, wenn dies nötig ist, um den SHA-1-Hash eindeutig zu bezeichnen. $ git log --abbrev-commit --pretty=oneline ca82a6d changed the version number @@ -73,40 +73,40 @@ Git kann auch selber eine Kurzform für Deine einzigartigen SHA-1 Werte erzeugen -Generell kann man sagen das acht bis zehn Zeichen mehr als ausreichend in einem Projekt sind, um eindeutig zu bleiben. Eines der größten Git Projekte, der Linux Kernel, fängt langsam an 12 von maximal 40 Zeichen zu nutzen um eindeutig zu bleiben. +Generell kann man sagen, dass acht bis zehn Zeichen mehr als ausreichend in einem Projekt sind, um eindeutig zu bleiben. Eines der größten Git-Projekte, der Linux-Kernel, fängt langsam an 12 von maximal 40 Zeichen zu nutzen, um eindeutig zu bleiben. -### EINE KURVE NOTIZ ÜBER SHA-1 ### +### Ein kurzer Hinweis zu SHA-1 ### -Eine Menge Leute machen sich Sorgen, dass ab einem zufälligen Punkt zwei Objekte im Repository vorhanden sind, die den gleichen SHA-1 hash wert haben. Was Dann? +Eine Menge Leute machen sich Sorgen, dass ab einem zufälligen Punkt zwei Objekte im Repository vorhanden sind, die den gleichen SHA-1-Hashwert haben. Was dann? -Wenn es passiert, dass bei einem commit, ein Objekt mit dem gleichen SHA-1 hash Wert im Repository vorhanden ist, wird Git sehen, dass das vorherige Objekt bereits in der Datenbank vorhanden ist und davon ausgehen, dass es bereits geschrieben wurde. Wenn Du versuchst das Objekt später wieder auszuchecken wirst Du immer die Daten des ersten Objekts bekommen. +Wenn es passiert, dass bei einem Commit, ein Objekt mit dem gleichen SHA-1-Hashwert im Repository vorhanden ist, wird Git sehen, dass das vorherige Objekt bereits in der Datenbank vorhanden ist und davon ausgehen, dass es bereits geschrieben wurde. Wenn Du versuchst, das Objekt später wieder auszuchecken, wirst Du immer die Daten des ersten Objekts bekommen. - + -Allerdings solltest Du Dir bewusst machen wie unglaublich unwahrscheinlich dieses Szenario ist. Die Länge des SHA-1 hashs beträgt 20 bytes oder 160bits. Die Anzahl der Objekte die benötigt werden, um eine 50% Chance einer Kollision zu haben, beträgt ungefähr 2^80 (die Formel zum berechnen der Kollisionswahrscheinlichkeit lautet ‚p = (n(n-1)/2) * (1/2^160))‘. 2^80 ist somit 1.2 x 10^24 oder eine Trilliarden. Das ist 1200 mal die Anzahl der Sandkörner die es auf der Erde gibt. +Allerdings solltest Du Dir bewusst machen, wie unglaublich unwahrscheinlich dieses Szenario ist. Die Länge des SHA-1-Hashs beträgt 20 Bytes oder 160 Bits. Die Anzahl der Objekte, die benötigt werden, um eine 50% Chance einer Kollision zu haben, beträgt ungefähr 2^80 (die Formel zum Berechnen der Kollisionswahrscheinlichkeit lautet `p = (n(n-1)/2) * (1/2^160)`). 2^80 ist somit 1.2 x 10^24 oder eine Trilliarde. Das ist 1200 Mal so viel, wie es Sandkörner auf der Erde gibt. -Hier ist ein Beispiel welches Dir eine Vorstellung davon geben wird was nötig ist um in SHA-1 eine Kollision zu bekommen. Wenn alle 6,5 Milliarden Menschen auf der Erde Programmieren würden und jeder jede Sekunde Code schreiben würde, der der gesamten Geschichte des Linux Kernels (1 Millionen Git Objekte) entspricht und diesen dann in ein gigantisches Git Repository übertragen würden, würde es fünf Jahre dauern bis das Repository genügend Objekte hätte um eine 50% Wahrscheinlichkeit für eine einzige SHA-1 Kollision aufzuweisen. Es ist wahrscheinlicher das jedes Mitglied Deines Programmierer Teams, unabhängig voneinander, in einer Nacht von Wölfen angegriffen und getötet wird. +Hier ist ein Beispiel, das Dir eine Vorstellung davon gibt, was nötig ist, um in SHA-1 eine Kollision zu bekommen. Wenn alle 6,5 Milliarden Menschen auf der Erde programmieren würden und jeder jede Sekunde Code schreiben würde, der der gesamten Geschichte des Linux-Kernels (1 Million Git-Objekte) entspricht, und diesen dann in ein gigantisches Git-Repository übertragen würde, würde es fünf Jahre dauern, bis das Repository genügend Objekte hätte, um eine 50% Wahrscheinlichkeit für eine einzige SHA-1-Kollision aufzuweisen. Es ist wahrscheinlicher, dass jedes Mitglied Deines Programmierer-Teams, unabhängig voneinander, in einer Nacht von Wölfen angegriffen und getötet wird. -### Branch Referenzen ### +### Branch-Referenzen ### -Am direktesten kannst Du einen Commit spezifizieren, wenn eine Branch Referenz direkt auf ihn zeigt. In dem Fall kannst Du in allen Git Befehlen, die ein Commit Objekt oder einen SHA-1 Wert erwarten, statt dessen den Branch Namen verwenden. Wenn Du z.B. den letzten Commit in einem Branch sehen willst, sind die folgenden Befehle äquivalent (vorausgesetzt der `topic1` Branch zeigt auf den Commit `ca82a6d`): +Am direktesten kannst Du einen Commit spezifizieren, wenn eine Branch-Referenz direkt auf ihn zeigt. In dem Fall kannst Du in allen Git-Befehlen, die ein Commit-Objekt oder einen SHA-1-Wert erwarten, stattdessen den Branch-Namen verwenden. Wenn Du z.B. den letzten Commit in einem Branch sehen willst, sind die folgenden Befehle äquivalent (vorausgesetzt der `topic1` Branch zeigt auf den Commit `ca82a6d`): $ git show ca82a6dff817ec66f44342007202690a93763949 $ git show topic1 -Wenn Du sehen willst, auf welchen SHA-1 Wert ein Branch zeigt, oder wie unsere Beispiele intern in SHA-1 Werte übersetzt aussähen, kannst Du den Git Plumbing Befehl `rev-parse` verwenden. In Kapitel 9 werden wir genauer auf Plumbing Befehle eingehen. Kurz gesagt ist `rev-parse` als eine Low-Level Operation gedacht und nicht dafür, im tagtäglichen Gebrauch eingesetzt zu werden. Aber es kann manchmal hilfreich sein, wenn man wissen muss, was unter der Haube vor sich geht: +Wenn Du sehen willst, auf welchen SHA-1-Wert ein Branch zeigt, oder wie unsere Beispiele intern in SHA-1-Werte übersetzt aussähen, kannst Du den Git-Plumbing-Befehl `rev-parse` verwenden. In Kapitel 9 werden wir genauer auf Plumbing-Befehle eingehen. Kurz gesagt ist `rev-parse` als eine Low-Level-Operation gedacht und nicht dafür, im tagtäglichen Gebrauch eingesetzt zu werden. Aber es kann manchmal hilfreich sein, wenn man wissen muss, was unter der Haube vor sich geht: $ git rev-parse topic1 ca82a6dff817ec66f44342007202690a93763949 @@ -116,7 +116,7 @@ Wenn Du sehen willst, auf welchen SHA-1 Wert ein Branch zeigt, oder wie unsere B -Eine andere Sache, die während Deiner täglichen Arbeit im Hintergrund passiert ist, dass Git ein sogenanntes Reflog führt, d.h. ein Log darüber, wohin Deine HEAD und Branch Referenzen in den letzten Monaten jeweils gezeigt haben. +Eine andere Sache, die während Deiner täglichen Arbeit im Hintergrund passiert ist, dass Git ein sogenanntes Reflog führt, d.h. ein Log darüber, wohin Deine HEAD- und Branch-Referenzen in den letzten Monaten jeweils gezeigt haben. @@ -133,7 +133,7 @@ Du kannst das Reflog mit `git reflog` anzeigen: -Immer dann, wenn ein Branch in irgendeiner Weise aktualisiert wird oder Du den aktuellen Branch wechselst, speichert Git diese Information ebenso im Reflog wie Commits und anderen Informationen. Wenn Du wissen willst, welches der fünfte Wert vor dem HEAD war, kannst Du die `@{n}` Referenz angeben, die Du in Reflog Ausgabe sehen kannst: +Immer dann, wenn ein Branch in irgendeiner Weise aktualisiert wird oder Du den aktuellen Branch wechselst, speichert Git diese Information ebenso im Reflog wie Commits und anderen Informationen. Wenn Du wissen willst, welches der fünfte Wert vor dem HEAD war, kannst Du die `@{n}` Referenz angeben, die Du in Reflog-Ausgabe sehen kannst: $ git show HEAD@{5} @@ -145,7 +145,7 @@ Außerdem kannst Du dieselbe Syntax verwenden, um eine Zeitspanne anzugeben. Um -Das zeigt dir, wo der `master` Branch gestern war. Diese Technik funktioniert nur mit Daten, die noch im Reflog sind, d.h. man kann sie nicht für Commits verwenden, die ein älter sind als ein paar Monate. +Das zeigt Dir, wo der `master` Branch gestern war. Diese Technik funktioniert nur mit Daten, die noch im Reflog sind, d.h. man kann sie nicht für Commits verwenden, die ein älter sind als ein paar Monate. @@ -170,13 +170,13 @@ Um Reflog Informationen in einem Format wie in `git log` anzeigen, kannst Du `gi -Es ist wichtig zu verstehen, dass das Reflog ausschließlich lokale Daten enthält. Es ist ein Log darüber, was Du in Deinem Repository getan hast, und es ist nie dasselbe wie in einem anderen Clone des selben Repositories. Direkt nachdem Du ein Repository geklont hast, ist das Reflog leer, weil noch keine weitere Aktivität stattgefunden hat. `git show HEAD@{2.months.ago}` funktioniert nur dann, wenn das Projekt mindestens zwei Monate alt ist – wenn Du es vor fünf Minuten erst geklont hast, erhältst Du keine Ergebnisse. +Es ist wichtig zu verstehen, dass das Reflog ausschließlich lokale Daten enthält. Es ist ein Log darüber, was Du in Deinem Repository getan hast, und es ist nie dasselbe wie in einem anderen Klon des selben Repositorys. Direkt nachdem Du ein Repository geklont hast, ist das Reflog leer, weil noch keine weitere Aktivität stattgefunden hat. `git show HEAD@{2.months.ago}` funktioniert nur dann, wenn das Projekt mindestens zwei Monate alt ist – wenn Du es vor fünf Minuten erst geklont hast, erhältst Du keine Ergebnisse. ### Vorfahren Referenzen ### - -Suppose you look at the history of your project: + Außerdem kann man Commits über ihre Vorfahren spezifizieren. Wenn Du ein `^` ans Ende einer Referenz setzt, schlägt Git den direkten Vorfahren dieses Commits nach. Nehmen wir an, Deine Historie sieht so aus: @@ -204,7 +204,7 @@ Du kannst jetzt den vorletzten Commit mit `HEAD^` referenzieren, d.h. „den dir -Außerdem kannst Du nach dem `^` eine Zahl angeben. Beispielsweise heißt `d921970^2`: „der zweite Vorfahr von d921970“. Diese Syntax ist allerdings nur für Merge Commits nützlich, die mehr als einen Vorfahren haben. Der erste Vorfahr ist der Branch auf dem Du Dich beim Merge befandest, der zweite ist der Commit auf dem Branch den Du gemergt hast. +Außerdem kannst Du nach dem `^` eine Zahl angeben. Beispielsweise heißt `d921970^2`: „der zweite Vorfahr von d921970“. Diese Syntax ist allerdings nur für Merge Commits nützlich, die mehr als einen Vorfahren haben. Der erste Vorfahr ist der Branch, auf dem Du Dich beim Merge befandest, der zweite ist der Commit auf dem Branch, den Du gemergt hast. $ git show d921970^ commit 1c002dd4b536e7479fe34593e72e6c6c1819e53b @@ -222,7 +222,7 @@ Außerdem kannst Du nach dem `^` eine Zahl angeben. Beispielsweise heißt `d9219 -Eine andere Vorfahren Spezifikation ist `~`. Dies bezieht sich ebenfalls auf den ersten Vorfahren, d.h. `HEAD~` und `HEAD^` sind äquivalent. Einen Unterschied macht es allerdings, wenn Du außerdem eine Zahl angibst. `HEAD~2` bedeutet z.B. „der Vorfahr des Vorfahren von HEAD“ oder „der n-te Vorfahr von HEAD“. Beispielsweise würde `HEAD~3` in der obigen Historie auf den folgenden Commit zeigen: +Eine andere Vorfahren-Spezifikation ist `~`. Dies bezieht sich ebenfalls auf den ersten Vorfahren, d.h. `HEAD~` und `HEAD^` sind äquivalent. Einen Unterschied macht es allerdings, wenn Du außerdem eine Zahl angibst. `HEAD~2` bedeutet z.B. „der Vorfahr des Vorfahren von HEAD“ oder „der n-te Vorfahr von HEAD“. Beispielsweise würde `HEAD~3` in der obigen Historie auf den folgenden Commit zeigen: $ git show HEAD~3 commit 1c3618887afb5fbcbea25b7c013f4e2114448b8d @@ -251,14 +251,14 @@ Du kannst diese Schreibweisen auch kombinieren und z.B. auf den zweiten Vorfahre -Nachdem Du jetzt einzelne Commits spezifizieren kannst, schauen wir uns an, wie man auf Commit Reihen zugreift. Dies ist vor allem nützlich, um Branches zu verwalten, z.B. wenn man viele Branches hat und solche Fragen beantworten will wie „Welche Änderungen befinden sich in diesem Branch, die ich noch nicht in meinen Hauptbranch gemergt habe“. +Nachdem Du jetzt einzelne Commits spezifizieren kannst, schauen wir uns an, wie man auf Commit-Reihen zugreift. Dies ist vor allem nützlich, um Branches zu verwalten, z.B. wenn man viele Branches hat und solche Fragen beantworten will wie „Welche Änderungen befinden sich in diesem Branch, die ich noch nicht in meinen Hauptbranch gemergt habe?“. -#### Zwei-Punkte Syntax #### +#### Zwei-Punkte-Syntax #### -Die gängigste Weise, Commit Reihen anzugeben, ist die Zwei-Punkte Notation. Allgemein gesagt evaluiert Git eine Reihe von Commits, die von einem Commit aus erreichbar sind, nicht aber von einem anderen (xxx ??? xxx). Nehmen wir z.B. an, Du hättest eine Commit Historie wie die folgende (Bild 6-1). +Die gängigste Weise, Commit-Reihen anzugeben, ist die Zwei-Punkte-Notation. Allgemein gesagt liefert Git damit eine Reihe von Commits, die von dem einem Commit aus erreichbar sind, allerdings nicht von dem anderen aus. Nehmen wir z.B. an, Du hättest eine Commit-Historie wie die folgende (Bild 6-1). @@ -266,7 +266,7 @@ Insert 18333fig0601.png -Du willst jetzt herausfinden, welche Änderungen in Deinem `experiment` Branch sind, die noch nicht in den `master` Branch gemergt wurden. Dann kannst Du ein Log dieser Commits mit `master..experiment` anzeigen, d.h. „alle Commits, die von `experiment` aus erreichbar sind, aber nicht von `master`“. Um die folgenden Beispiele ein bisschen abzukürzen und deutlicher zu machen, verwende ich für die Commit Objekte die Buchstaben aus dem Diagramm anstelle der tatsächlichen Log Ausgabe: +Du willst jetzt herausfinden, welche Änderungen in Deinem `experiment`-Branch sind, die noch nicht in den `master`-Branch gemergt wurden. Dann kannst Du ein Log dieser Commits mit `master..experiment` anzeigen, d.h. „alle Commits, die von `experiment` aus erreichbar sind, aber nicht von `master`“. Um die folgenden Beispiele ein bisschen abzukürzen und deutlicher zu machen, verwende ich für die Commit-Objekte die Buchstaben aus dem Diagramm anstelle der tatsächlichen Log Ausgabe: $ git log master..experiment D @@ -274,7 +274,7 @@ Du willst jetzt herausfinden, welche Änderungen in Deinem `experiment` Branch s -Wenn Du allerdings – anders herum – diejenigen Commits anzeigen willst, die in `master`, aber noch nicht in `experiment` sind, kannst Du die Branch Namen umdrehen: `experiment..master` zeigt „alles in `master`, das nicht in `experiment` enthalten ist“. +Wenn Du allerdings – anders herum – diejenigen Commits anzeigen willst, die in `master`, aber noch nicht in `experiment` sind, kannst Du die Branch-Namen umdrehen: `experiment..master` zeigt „alles in `master`, das nicht in `experiment` enthalten ist“. $ git log experiment..master F @@ -282,21 +282,21 @@ Wenn Du allerdings – anders herum – diejenigen Commits anzeigen willst, die -Dies ist nützlich, wenn Du vorhast, den `experiment` Branch zu aktualisieren, und anzeigen willst, was Du dazu mergen wirst. Oder wenn Du vorhast, in ein Remote Repository zu pushen und sehen willst, welche Commits betroffen sind: +Dies ist nützlich, wenn Du vorhast, den `experiment`-Branch zu aktualisieren, und anzeigen willst, was Du dazu mergen wirst. Oder wenn Du vorhast, in ein Remote-Repository zu pushen und sehen willst, welche Commits betroffen sind: $ git log origin/master..HEAD - + + -Dieser Befehl zeigt Dir alle Commits im gegenwärtigen, lokalen Branch, die noch nicht im `master` Branch des `origin` Repositories sind. D.h., der Befehl listet diejenigen Commits auf, die auf den Server transferiert würden, wenn Du `git push` benutzt und der aktuelle Branch `origin/master` trackt. Du kannst mit dieser Syntax außerdem eine Seite der beiden Punkte leer lassen. Git nimmt dann an, Du meinst an dieser Stelle HEAD. Z.B. kannst Du dieselben Commits wie im vorherigen Beispiel auch mit `git log origin/master..` anzeigen lassen. Git fügt dann HEAD auf der rechten Seite ein. +Dieser Befehl zeigt Dir alle Commits im gegenwärtigen, lokalen Branch, die noch nicht im `master`-Branch des `origin` Repositorys sind. D.h., der Befehl listet diejenigen Commits auf, die auf den Server transferiert würden, wenn Du `git push` benutzt und der aktuelle Branch `origin/master` trackt. Du kannst mit dieser Syntax außerdem eine Seite der beiden Punkte leer lassen. Git nimmt dann an, Du meinst an dieser Stelle HEAD. Z.B. kannst Du dieselben Commits wie im vorherigen Beispiel auch mit `git log origin/master..` anzeigen lassen. Git fügt dann HEAD auf der rechten Seite ein. -#### Mehrfache Punkte (xxx) #### +#### Mehrere Bezugspunkte #### -Die Zwei-Punkte Syntax ist eine nützliche Abkürzung, aber möglicherweise willst Du mehr als nur zwei Branches angeben, um z.B. herauszufinden, welche Commits in einem beliebigen anderen Branch enthalten sind, ausgenommen in demjenigen, auf dem Du Dich gerade befindest. Dazu kannst Du in Git das `^` Zeichen oder `--not` verwenden, um Commits auszuschließen, die von den angegebenen Referenzen aus erreichbar sind. D.h., die folgenden drei Befehle sind äquivalent: +Die Zwei-Punkte-Syntax ist eine nützliche Abkürzung, aber möglicherweise willst Du mehr als nur zwei Branches angeben, um z.B. herauszufinden, welche Commits in einem beliebigen anderen Branch enthalten sind, ausgenommen in demjenigen, auf dem Du Dich gerade befindest. Dazu kannst Du in Git das `^` Zeichen oder `--not` verwenden, um Commits auszuschließen, die von den angegebenen Referenzen aus erreichbar sind. D.h., die folgenden drei Befehle sind äquivalent: $ git log refA..refB $ git log ^refA refB @@ -304,7 +304,7 @@ Die Zwei-Punkte Syntax ist eine nützliche Abkürzung, aber möglicherweise will -Das ist praktisch, weil Du auf diese Weise mehr als nur zwei Referenzen angeben kannst, was mit der Zwei-Punkte Notation nicht geht. Wenn Du beispielsweise alle Commits sehen willst, die von `refA` oder `refB` erreichbar sind, nicht aber von `refC`, dann kannst Du folgende (äquivalente) Befehle benutzen: +Das ist praktisch, weil Du auf diese Weise mehr als nur zwei Referenzen angeben kannst, was mit der Zwei-Punkte-Notation nicht geht. Wenn Du beispielsweise alle Commits sehen willst, die von `refA` oder `refB` erreichbar sind, nicht aber von `refC`, dann kannst Du folgende (äquivalente) Befehle benutzen: $ git log refA refB ^refC $ git log refA refB --not refC @@ -314,12 +314,12 @@ Das ist praktisch, weil Du auf diese Weise mehr als nur zwei Referenzen angeben Damit hast Du ein sehr mächtiges System von Abfragen zur Verfügung, mit denen Du herausfinden kannst, was in welchen Deiner Branches enthalten ist. -#### Drei-Punkte Syntax #### +#### Drei-Punkte-Syntax #### - + + -Die letzte wichtige Syntax, mit der man Commit Reihen spezifizieren kann, ist die Drei-Punkte Syntax, die alle Commits anzeigt, die in einer der beiden Referenzen enthalten sind, aber nicht in beiden. Schau Dir noch mal die Commit Historie in Bild 6-1- an. Wenn Du diejenigen Commits anzeigen willst, die in den `master` und `experiment` Branches, nicht aber in beiden Branches gleichzeitig enthalten sind, dann kannst Du folgendes tun: +Die letzte wichtige Syntax, mit der man Commit-Reihen spezifizieren kann, ist die Drei-Punkte-Syntax, die alle Commits anzeigt, die in einer der beiden Referenzen enthalten sind, aber nicht in beiden. Schau Dir noch mal die Commit Historie in Bild 6-1 an. Wenn Du diejenigen Commits anzeigen willst, die in den `master`- und `experiment`-Branches, nicht aber in beiden Branches gleichzeitig enthalten sind, dann kannst Du folgendes tun: $ git log master...experiment F @@ -329,7 +329,7 @@ Die letzte wichtige Syntax, mit der man Commit Reihen spezifizieren kann, ist di -Dies gibt Dir wiederum ein normale `log` Ausgabe, aber zeigt nur die Informationen dieser vier Commits – wie üblich sortiert nach dem Commit Datum. +Dies gibt Dir wiederum ein normale `log` Ausgabe, aber zeigt nur die Informationen dieser vier Commits – wie üblich sortiert nach dem Commit-Datum. @@ -348,10 +348,10 @@ Mit diesen Hilfsmitteln kannst Du noch einfacher und genauer angeben, welche Com ## Interaktives Stagen ## - + + -Git umfasst eine Reihe von Skripten, die so manche Aufgabe auf der Kommandozeile leichter machen. Im folgenden schauen wir uns einige interaktive Befehle an, die dabei hilfreich sein können, wenn man Änderungen in vielen Dateien vorgenommen hat, aber nur einige Änderungen gezielt committen will – nicht alles auf einmal in einem riesigen Commit. Auf diese Weise kann man Commits logisch gruppieren und macht es anderen Entwicklern damit leichter, sie zu verstehen. Wenn Du `git add` mit der `-i` oder `--interactive` Option verwendest, geht Git in einen interaktiven Shell Modus, der in etwa wie folgt aussieht: +Git umfasst eine Reihe von Skripten, die so manche Aufgabe auf der Kommandozeile leichter machen. Im Folgenden schauen wir uns einige interaktive Befehle an, die dabei hilfreich sein können, wenn man Änderungen in vielen Dateien vorgenommen hat, aber nur einige Änderungen gezielt committen will – nicht alles auf einmal in einem riesigen Commit. Auf diese Weise kann man Commits logisch gruppieren und macht es anderen Entwicklern damit leichter, sie zu verstehen. Wenn Du `git add` mit der `-i` oder `--interactive` Option verwendest, geht Git in einen interaktiven Shell-Modus, der in etwa wie folgt aussieht: $ git add -i staged unstaged path @@ -366,18 +366,18 @@ Git umfasst eine Reihe von Skripten, die so manche Aufgabe auf der Kommandozeile -Wie Du siehst zeigt dieser Befehl eine andere Ansicht der Staging Area an – im wesentlichen also die Information, die Du auch mit `git status` erhältst, aber anders formatiert, ein bisschen kürzer (xxx succinct? xxx) und informativer. Sie listet alles Änderungen, die in der Staging Area enthalten sind, auf der linken Seite, und alle anderen Änderungen auf der rechten Seite. +Wie Du siehst, zeigt dieser Befehl eine andere Ansicht der Staging-Area an – im Wesentlichen also die Information, die Du auch mit `git status` erhältst, aber anders formatiert, kurz und knapp, und informativer. Sie listet alle Änderungen, die in der Staging-Area enthalten sind, auf der linken Seite, und alle anderen Änderungen auf der rechten Seite. Danach folgt eine Liste von Befehlen wie, u.a., Dateien ganz oder teilweise stagen und unstagen, nicht versionskontrollierte Dateien hinzufügen, Diffs der gestageten Änderungen anzeigen etc. -### Dateien stagen und unstagen (xxx) ### +### Hinzufügen und Enfernen von Dateien aus der Staging-Area ### -Wenn Du am `What now>` Prompt `2` oder `u` eingibst, wirst Du als nächstes gefragt, welche Dateien Du stagen willst: +Wenn Du am `What now>` Prompt `2` oder `u` eingibst, wirst Du als Nächstes gefragt, welche Dateien Du stagen willst: What now> 2 staged unstaged path @@ -399,7 +399,7 @@ Um z.B. die TODO und index.html Dateien zu stagen, gibst Du die jeweiligen Zahle -Das `*` neben den Dateinamen bedeutet, dass die Datei ausgewählt ist und zur Staging Area hinzugefügt werden wird, sobald Du (bei einem sonst leeren `Update>>` Prompt) Enter drückst: +Das `*` neben den Dateinamen bedeutet, dass die Datei ausgewählt ist und zur Staging-Area hinzugefügt werden wird, sobald Du (bei einem sonst leeren `Update>>` Prompt) Enter drückst: Update>> updated 2 paths @@ -415,7 +415,7 @@ Das `*` neben den Dateinamen bedeutet, dass die Datei ausgewählt ist und zur St -Du kannst sehen, dass die TODO und index.html Dateien jetzt gestaged sind, während simplegit.rb immer noch ungestaged ist. Wenn Du die TODO unstagen willst, kannst Du die Option `3` oder `r` (für revert) nutzen: +Du kannst sehen, dass die TODO und index.html Dateien jetzt gestaget sind, während simplegit.rb immer noch ungestaget ist. Wenn Du die TODO unstagen willst, kannst Du die Option `3` oder `r` (für revert) nutzen: *** Commands *** 1: status 2: update 3: revert 4: add untracked @@ -435,7 +435,7 @@ Du kannst sehen, dass die TODO und index.html Dateien jetzt gestaged sind, währ -Wenn Du wiederum Deinen Git status ansiehst, kannst Du sehen dass Du die TODO ungestaged hast. +Wenn Du wiederum Deinen Git-Status ansiehst, kannst Du sehen, dass Du die TODO ungestaget hast. *** Commands *** 1: status 2: update 3: revert 4: add untracked @@ -448,7 +448,7 @@ Wenn Du wiederum Deinen Git status ansiehst, kannst Du sehen dass Du die TODO un -Um einen Diff dessen zu sehen, das Du gestaged hast, kannst Du den Befehl `6` oder `d` (für diff) nutzen. Dieser zeigt Dir eine Liste der gestageden Dateien, und Du kannst diejenigen auswählen, von denen Du den gestageden Diff sehen willst. Dies ähnelt sehr dem Befehl `git diff --cached` auf der Kommandozeile. +Um einen Diff dessen zu sehen, das Du gestaget hast, kannst Du den Befehl `6` oder `d` (für diff) nutzen. Dieser zeigt Dir eine Liste der gestageten Dateien, und Du kannst diejenigen auswählen, von denen Du den gestageten Diff sehen willst. Dies ähnelt sehr dem Befehl `git diff --cached` auf der Kommandozeile. *** Commands *** 1: status 2: update 3: revert 4: add untracked @@ -472,14 +472,14 @@ Um einen Diff dessen zu sehen, das Du gestaged hast, kannst Du den Befehl `6` od -Mit diesen grundlegenden Befehlen kannst Du den interaktiven add Modus nutzen um Dir den Umgang mit Deiner Staging area etwas zu erleichtern. +Mit diesen grundlegenden Befehlen kannst Du den interaktiven Hinzufüge-Modus nutzen, um Dir den Umgang mit Deiner Staging-Area etwas zu erleichtern. ### Patches stagen ### -Es ist für Git auch möglich bestimmte Teile einer Datei zu stagen und nicht den Rest. Wenn Du z. B. 2 Veränderungen an der simplegit.rb machst und eine davon stagen willst und die andere nicht, ist dies sehr einfach in Git möglich. Wähle `5` oder `p` (für patch) auf dem interactive prompt. Git wird Dich fragen welche Dateien Du teilweise stagen willst; dann wird es für jeden Abschnitt der gewählten Dateien diff hunks ausgeben und Dich jeweils einzeln fragen ob Du sie stagen willst. +Es ist für Git auch möglich, bestimmte Teile einer Datei zu stagen und nicht den Rest. Wenn Du z.B. zwei Veränderungen an der simplegit.rb machst und eine davon stagen willst und die andere nicht, ist dies sehr einfach in Git möglich. Wähle `5` oder `p` (für patch) auf dem interaktiven Prompt. Git wird Dich fragen, welche Dateien Du teilweise stagen willst; dann wird es für jeden Abschnitt der gewählten Dateien Diff-Ausschnitte ausgeben und Dich jeweils einzeln fragen, ob Du sie stagen willst. diff --git a/lib/simplegit.rb b/lib/simplegit.rb index dd5ecc4..57399e0 100644 @@ -498,7 +498,7 @@ Es ist für Git auch möglich bestimmte Teile einer Datei zu stagen und nicht de -Du hast an diesem Punkt viele Options. Tippe `?` ein um eine Liste der Möglichkeiten zu bekommen: +Du hast an diesem Punkt viele Optionen. Tippe `?` ein, um eine Liste der Möglichkeiten zu bekommen: Stage this hunk [y,n,a,d,/,j,J,g,e,?]? ? y - stage this hunk @@ -517,7 +517,7 @@ Du hast an diesem Punkt viele Options. Tippe `?` ein um eine Liste der Möglichk -Im Allgemeinen, wirst Du `y` oder `n` nutzen wenn Du jeden Hunk stagen willst, aber alle Hunks in bestimmten Dateien zu stagen oder die Entscheidung für einen Hunk auf später zu verschieben kann auch sehr hilfreich sein. Wenn Du nur einen Teil der Datei stagest und den anderen ungestaged lässt, sieht Deine Status-Ausgabe in etwa so aus: +Im Allgemeinen, wirst Du `y` oder `n` nutzen, wenn Du jeden Ausschnitt stagen willst, aber alle Ausschnitte in bestimmten Dateien zu stagen oder die Entscheidung für einen Ausschnitt auf später zu verschieben kann auch sehr hilfreich sein. Wenn Du nur einen Teil der Datei stagest und den anderen ungestaget lässt, sieht Deine Status-Ausgabe in etwa so aus: What now> 1 staged unstaged path @@ -527,11 +527,11 @@ Im Allgemeinen, wirst Du `y` oder `n` nutzen wenn Du jeden Hunk stagen willst, a -Der Status der simplegit.rb ist interessant. Er zeigt dir, dass ein paar Zeilen gestagd und ein paar ungestaged sind. Du hast diese Datei teilweise gestaged. An dieser Stelle kannst Du das interaktive add Skript verlassen und `git commit` ausführen, um die teilweise gestageden Dateien zu commiten. +Der Status der simplegit.rb ist interessant. Er zeigt Dir, dass ein paar Zeilen gestaget und ein paar ungestaget sind. Du hast diese Datei teilweise gestaget. An dieser Stelle kannst Du das interaktive Hinzufüge-Skript verlassen und `git commit` ausführen, um die teilweise gestageten Dateien zu commiten. -Letztendlich musst Du nicht den interactive add Modus nutzen um Dateien teilweise zu stagen – Du kannst das gleiche Skript starten in dem Du `git add -p` oder `git add --patch` auf der Kommandozeile eingibst. +Letztendlich musst Du nicht den interaktiven Hinzufüge-Modus nutzen, um Dateien teilweise zu stagen – Du kannst das gleiche Skript starten, indem Du `git add -p` oder `git add --patch` auf der Kommandozeile eingibst. ## Stashen ## @@ -542,14 +542,14 @@ Während man an einer bestimmten Funktion eines Projekts arbeitet, ist es oft so -Beim Stashen werden die aus Deinem Arbeitsverzeichnis noch nicht committeten Änderungen – also Deine geänderten beobachteten Dateien und die in der Staging Area enthaltenen Dateien – in einem Stack voller unfertiger Änderungen gespeichert. Diese kannst Du dann jederzeit wieder vom Stack holen und auf Dein Arbeitsverzeichnis anwenden. +Beim Stashen werden die aus Deinem Arbeitsverzeichnis noch nicht committeten Änderungen – also Deine geänderten beobachteten Dateien und die in der Staging-Area enthaltenen Dateien – in einem Stack voller unfertiger Änderungen gespeichert. Diese kannst Du dann jederzeit wieder vom Stack holen und auf Dein Arbeitsverzeichnis anwenden. ### Stash verwenden ### -Um dies zu demonstrieren, gehst Du in Dein Projekt und beginnst an ein paar Dateien zu arbeiten und merkst ein paar dieser Änderungen in der Staging Area vor. Wenn Du den Befehl `git status` ausführst, siehst Du, dass sich einige Dateien seit dem letzen Commit verändert haben. +Um dies zu demonstrieren, gehst Du in Dein Projekt und beginnst an ein paar Dateien zu arbeiten und merkst ein paar dieser Änderungen in der Staging-Area vor. Wenn Du den Befehl `git status` ausführst, siehst Du, dass sich einige Dateien seit dem letzen Commit verändert haben. $ git status # On branch master @@ -566,7 +566,7 @@ Um dies zu demonstrieren, gehst Du in Dein Projekt und beginnst an ein paar Date -Jetzt kommt der Zeitpunkt an dem Du den aktuellen Branch wechseln möchtest. Allerdings willst Du den aktuellen Zustand auch nicht committen, da Deine Arbeit noch nicht ganz fertiggestellt ist. Darum legst Du Deine Änderungen jetzt in einem Stash ab. Um diesen neuen Stash auf dem Stack abzulegen, verwendest Du den Befehl `git stash`: +Jetzt kommt der Zeitpunkt, an dem Du den aktuellen Branch wechseln möchtest. Allerdings willst Du den aktuellen Zustand auch nicht committen, da Deine Arbeit noch nicht ganz fertiggestellt ist. Darum legst Du Deine Änderungen jetzt in einem Stash ab. Um diesen neuen Stash auf dem Stack abzulegen, verwendest Du den Befehl `git stash`: $ git stash Saved working directory and index state \ @@ -576,11 +576,11 @@ Jetzt kommt der Zeitpunkt an dem Du den aktuellen Branch wechseln möchtest. All -In Deinem Arbeitsverzeichnis befinden sich jetzt keine geänderten Dateien mehr und die Staging Area ist auch leer: +In Deinem Arbeitsverzeichnis befinden sich jetzt keine geänderten Dateien mehr und die Staging-Area ist auch leer: $ git status # On branch master - nothing to commit (working directory clean) + nothing to commit, working directory clean @@ -593,7 +593,7 @@ In diesem Zustand, kannst Du in beliebig andere Branches wechseln und an etwas a -In diesem Beispiel waren bereits zwei Stashes auf dem Stack vorhanden. Sie wurden zu einem früheren Zeitpunkt gespeichert. Dir stehen jetzt also drei verschiedene Stashes auf dem Stack zur Verfügung. Mit dem Befehl `git stash apply` kannst Du die zuletzt gestashten Änderungen in Deinem Arbeitsverzeichnis wiederherstellen. Git zeigt diesen Befehlsaufruf auch bei Ausführen des Befehls `git stash` als Hilfestellung an. Wenn Du einen der älteren Stashes auf Dein Arbeitsverzeichnis anwenden willst, kannst Du den entsprechenden Stashnamen an den Befehl anhängen: `git stash apply stash@{2}`. Wie Du bereits gesehen hast, verwendet Git die zuletzt gestashten Änderungen und versucht diese im Arbeitsverzeichnis wiederherzuellen, wenn der Stashname nicht angegeben wird: +In diesem Beispiel waren bereits zwei Stashes auf dem Stack vorhanden. Sie wurden zu einem früheren Zeitpunkt gespeichert. Dir stehen jetzt also drei verschiedene Stashes auf dem Stack zur Verfügung. Mit dem Befehl `git stash apply` kannst Du die zuletzt gestashten Änderungen in Deinem Arbeitsverzeichnis wiederherstellen. Git zeigt diesen Befehlsaufruf auch bei Ausführen des Befehls `git stash` als Hilfestellung an. Wenn Du einen der älteren Stashes auf Dein Arbeitsverzeichnis anwenden willst, kannst Du den entsprechenden Stashnamen an den Befehl anhängen: `git stash apply stash@{2}`. Wie Du bereits gesehen hast, verwendet Git die zuletzt gestashten Änderungen und versucht diese im Arbeitsverzeichnis wiederherzustellen, wenn der Stashname nicht angegeben wird: $ git stash apply # On branch master @@ -610,7 +610,7 @@ Wie Du sehen kannst, stellt Git die Dateien wieder her, die Du in einem Stash ge -Die Änderungen an den Dateien wurden in Deinem Arbeitsverzeichnis wiederhergestellt. Allerdings ist die Datei, die beim Stashen in der Staging Area vorhanden war, nicht automatisch wieder in die Staging Area gewandert. Wenn Du die Option `--index` an den Befehl `git stash apply` anhängst, wird Git versuchen, die Dateien wieder zu stagen. Wenn Du diesen Befehl angewandt hättest, wäre Dein Arbeitsverzeichnis und Deine Staging Area im exakt gleichen Zustand, wie vor dem Stashen: +Die Änderungen an den Dateien wurden in Deinem Arbeitsverzeichnis wiederhergestellt. Allerdings ist die Datei, die beim Stashen in der Staging-Area vorhanden war, nicht automatisch wieder in die Staging-Area gewandert. Wenn Du die Option `--index` an den Befehl `git stash apply` anhängst, wird Git versuchen, die Dateien wieder zu stagen. Wenn Du diesen Befehl angewandt hättest, wäre Dein Arbeitsverzeichnis und Deine Staging-Area im exakt gleichen Zustand, wie vor dem Stashen: $ git stash apply --index # On branch master @@ -627,7 +627,7 @@ Die Änderungen an den Dateien wurden in Deinem Arbeitsverzeichnis wiederhergest -Mit der Option `apply` wird nur versucht die Änderungen wiederherzustellen. Der Stash an sich bleibt weiterhin auf dem Stack vorhanden. Um diesen zu entfernen kannst Du den Befehl `git stash drop` zusammen mit dem Namen des Stashes anwenden: +Mit der Option `apply` wird nur versucht die Änderungen wiederherzustellen. Der Stash an sich bleibt weiterhin auf dem Stack vorhanden. Um diesen zu entfernen, kannst Du den Befehl `git stash drop` zusammen mit dem Namen des Stashes anwenden: $ git stash list stash@{0}: WIP on master: 049d078 added the index file @@ -655,12 +655,12 @@ An dieser Stelle noch einmal der Hinweis, dass Git den zuletzt erstellten Stash $ git stash show -p | git apply -R - + Wenn Du dieses Feature öfters benötigst, ist es wahrscheinlich sinnvoll, einen Alias `stash-unapply` in Git dafür anzulegen: $ git config --global alias.stash-unapply '!git stash show -p | git apply -R' - $ git stash + $ git stash apply $ #... work work work $ git stash-unapply @@ -695,18 +695,18 @@ Damit ist es auf einfache Art und Weise möglich, die gestashten Änderungen in -Beim Arbeiten mit Git kommt es häufig vor, dass man seine Commit-Historie aus irgendeinem Grund noch einmal ändern möchte. Und das Tolle an Git ist, dass es Dir die Möglichkeit bietet, Entscheidungen erst im allerletzten Moment zu treffen. Zum Beispiel bietet Dir Git mit Hilfe der Staging-Area die Möglichkeit alle Dateien zu sammeln und kurz vor einem Commit zu entscheiden, welche Daten alle in einem Commit wandern sollen. Du kannst auch Deine Dateien, die sich geändert haben, aber noch nicht ins Repository eingepflegt werden sollen, mit dem Stash-Kommando in einem Zwischenspeicher ablegen. Außerdem kannst Du bereits verfasste Commits nachträglich noch einmal ändern, sodass sich die Historie so ändert, als wäre sie ganz anders vorangeschritten. Das kann man zum Beispiel durch Änderung der Reihenfolge der Commits, durch Ändern von Commit-Nachrichten, durch Modifikationen an Dateien innerhalb eines Commits, durch Zusammenfügen zweier Commits zu einem Commit oder durch Löschen eines Commits erreichen. Und das besondere daran: Das alles bevor Du Deine Arbeit mit anderen teilst und veröffentlichst. +Beim Arbeiten mit Git kommt es häufig vor, dass man seine Commit-Historie aus irgendeinem Grund noch einmal ändern möchte. Und das Tolle an Git ist, dass es Dir die Möglichkeit bietet, Entscheidungen erst im allerletzten Moment zu treffen. Zum Beispiel bietet Dir Git mit Hilfe der Staging-Area die Möglichkeit, alle Dateien zu sammeln und kurz vor einem Commit zu entscheiden, welche Daten alle in einen Commit wandern sollen. Du kannst auch Deine Dateien, die sich geändert haben, aber noch nicht ins Repository eingepflegt werden sollen, mit dem Stash-Kommando in einem Zwischenspeicher ablegen. Außerdem kannst Du bereits verfasste Commits nachträglich noch einmal ändern, sodass sich die Historie so ändert, als wäre sie ganz anders vorangeschritten. Das kann man zum Beispiel durch Änderung der Reihenfolge der Commits, durch Ändern von Commit-Nachrichten, durch Modifikationen an Dateien innerhalb eines Commits, durch Zusammenfügen zweier Commits zu einem Commit oder durch Löschen eines Commits erreichen. Und das Besondere daran: Das alles, bevor Du Deine Arbeit mit anderen teilst und veröffentlichst. -In diesem Kapitel werden wir die nützlichen Arbeitsschritte besprechen, die Dir helfen Deine Commit-Historie Deinen Wünschen entsprechend zu gestalten, sodass Du Dein Ergebnis danach mit anderen teilen kannst und es damit Deinem gewünschten Ergebnis entspricht. +In diesem Kapitel werden wir die nützlichen Arbeitsschritte besprechen, die Dir helfen, Deine Commit-Historie Deinen Wünschen entsprechend zu gestalten, sodass Du Dein Ergebnis danach mit anderen teilen kannst und es damit Deinem gewünschten Ergebnis entspricht. ### Ändern des letzten Commits ### -Am häufigsten möchte man wahrscheinlich seinen letzten durchgeführten Commit noch einmal nachträglich ändern. Meist sind es zwei Dinge, die man verändern möchte: Änderung der eingegebenen Commit-Nachricht oder den eigentlich Inhalt des Schnappschusses durch Hinzufügen, Ändern oder Löschen von Dateien. +Am häufigsten möchte man wahrscheinlich seinen letzten durchgeführten Commit noch einmal nachträglich ändern. Meist sind es zwei Dinge, die man verändern möchte: Änderung der eingegebenen Commit-Nachricht oder den eigentlichen Inhalt des Schnappschusses durch Hinzufügen, Ändern oder Löschen von Dateien. @@ -716,37 +716,37 @@ Die letzte Commit-Nachricht noch einmal zu ändern ist sehr einfach: -Nach Eingabe dieses Befehls wird der Texteditor mit dem Inhalt der letzten Commit-Nachricht geöffnet. Jetzt hat man Gelegenheit diesen Text zu ändern. Nach dem Speichern und Schließen des Editors, wird die Commit-Nachricht des letzten Commits entsprechend angepasst. Der alte Commit ist dadurch nicht mehr vorhanden und Du erhälst einen neuen Commit mit dem gleichen Inhalt und Deiner neuen Commit-Nachricht. +Nach Eingabe dieses Befehls wird der Texteditor mit dem Inhalt der letzten Commit-Nachricht geöffnet. Jetzt hat man Gelegenheit diesen Text zu ändern. Nach dem Speichern und Schließen des Editors, wird die Commit-Nachricht des letzten Commits entsprechend angepasst. Der alte Commit ist dadurch nicht mehr vorhanden und Du erhältst einen neuen Commit mit dem gleichen Inhalt und Deiner neuen Commit-Nachricht. -Wenn Du Deine Änderungen bereits eingecheckt hast und den Schnappschuss nachträglich durch Hinzufügen oder Ändern von Dateien noch einmal ändern möchtest, läuft das im Prinzip auf die gleiche Art und Weise ab. Meist kommt so etwas vor, weil man vergessen hat eine neu erstellte Datei zu stagen. Wenn so etwas passiert kannst Du folgendes machen: Führe Deine gewünschte Änderungen durch Ändern oder Hinzufügen einer Datei aus und stage dieses Ergebnis mit dem Befehl `git add`. Alternativ kannst Du auch mit dem Befehl `git rm` eine Datei aus dem Repository entfernen. Wenn die Staging Area Dein gewünschtes Ergebnis enthält, führst Du einfach den Befehl `git commit --amend` aus. Der neue Commit enthält nun die Änderungen aus dem alten Commit plus die Änderungen aus Deiner Staging Area. +Wenn Du Deine Änderungen bereits eingecheckt hast und den Schnappschuss nachträglich durch Hinzufügen oder Ändern von Dateien noch einmal ändern möchtest, läuft das im Prinzip auf die gleiche Art und Weise ab. Meist kommt so etwas vor, weil man vergessen hat, eine neu erstellte Datei zu stagen. Wenn so etwas passiert, kannst Du Folgendes machen: Führe Deine gewünschte Änderungen durch Ändern oder Hinzufügen einer Datei aus und stage dieses Ergebnis mit dem Befehl `git add`. Alternativ kannst Du auch mit dem Befehl `git rm` eine Datei aus dem Repository entfernen. Wenn die Staging-Area Dein gewünschtes Ergebnis enthält, führst Du einfach den Befehl `git commit --amend` aus. Der neue Commit enthält nun die Änderungen aus dem alten Commit plus die Änderungen aus Deiner Staging-Area. -Mit dem Befehl `--amend` sollte man vorsichtig umgehen, weil mit jeder nachträglichen Modifikation eines Commits, ändert sich auch die SHA-1 Prüfsumme. Das Ändern des letzten Commits hat ein ähnliches Verhalten wie das Durchführen eines Rebase-Befehls. Deshalb sollte man einen Commit niemals nachträglich anpassen, wenn dieser bereits veröffentlicht wurde. +Mit dem Befehl `--amend` sollte man vorsichtig umgehen, weil sich mit jeder nachträglichen Modifikation eines Commits auch die SHA-1-Prüfsumme ändert. Das Ändern des letzten Commits hat ein ähnliches Verhalten wie das Durchführen eines Rebase-Befehls. Deshalb sollte man einen Commit niemals nachträglich anpassen, wenn dieser bereits veröffentlicht wurde. ### Änderung von mehreren Commit-Nachrichten ### -Um einen Commit, der etwas weiter in der Historie zurückliegt, zu ändern, hilft einem der Befehl `--amend` nicht weiter. Man benötigt dazu ein etwas mächtigeres und komplexeres Werkzeug. Für diese Aufgabe kann man den Rebase Befehl, den wir bereits kennengelernt haben, auf eine etwas andere Art und Weise nutzen. Anstatt den Rebase auf einen HEAD eines anderen Commits auszuführen, führt man den Rebase auf genau dem gleichen Commit aus, auf dem er bereits basiert. Dazu müssen wir nur den interaktiven Modus des Rebase-Befehls nutzen. Dieser bietet einem die Möglichkeit bei jedem Commit, der geändert werden soll, zu stoppen. Dann kann man seine Änderungen an den Dateien oder an der Commit-Nachricht entsprechend einpflegen und mit dem nächsten Commit fortfahren. Um einen interaktiven Rebase durchzuführen muss man die Option `-i` an den Befehl `git rebase` anhängen. Außerdem musst Du natürlich bestimmen, wie viele Commits Du ändern möchtest. Dazu musst Du den Commit angeben, auf welchem der Rebase basieren soll. +Um einen Commit, der etwas weiter in der Historie zurückliegt, zu ändern, hilft einem der Befehl `--amend` nicht weiter. Man benötigt dazu ein etwas mächtigeres und komplexeres Werkzeug. Für diese Aufgabe kann man den Rebase-Befehl, den wir bereits kennengelernt haben, auf eine etwas andere Art und Weise nutzen. Anstatt den Rebase auf einen HEAD eines anderen Commits auszuführen, führt man den Rebase auf genau dem gleichen Commit aus, auf dem er bereits basiert. Dazu müssen wir nur den interaktiven Modus des Rebase-Befehls nutzen. Dieser bietet einem die Möglichkeit bei jedem Commit, der geändert werden soll, zu stoppen. Dann kann man seine Änderungen an den Dateien oder an der Commit-Nachricht entsprechend einpflegen und mit dem nächsten Commit fortfahren. Um einen interaktiven Rebase durchzuführen, muss man die Option `-i` an den Befehl `git rebase` anhängen. Außerdem musst Du natürlich bestimmen, wie viele Commits Du ändern möchtest. Dazu musst Du den Commit angeben, auf welchem der Rebase basieren soll. -Wenn Du zum Beispiel die letzten drei, oder eine oder mehrere der letzten drei Commit-Nachrichten ändern möchtest, musst Du zusätzlich zu dem Befehl `git rebase -i` den übergeordneten Commit (also dem Commit, der in der Historie genau ein Commit zurückliegt) des letzten Commits, den Du ändern möchtest, angeben. Bei drei Commit-Nachrichten müsste das Argument also `HEAD~2^` beziehungsweise `HEAD~3` lauten. Wahrscheinlich fällt es Dir leichter das Argument `~3` zu merken, weil Du ja schließlich auf die letzten drei Einträge verweisen möchtest. Du solltest Dir aber bewusst sein, dass Du auf den viertältesten Commit verweisen musst, also dem übergeordneten Commit, den Du ändern möchtest. +Wenn Du zum Beispiel die letzten drei, oder eine oder mehrere der letzten drei Commit-Nachrichten ändern möchtest, musst Du zusätzlich zu dem Befehl `git rebase -i` den übergeordneten Commit (also dem Commit, der in der Historie genau ein Commit zurückliegt) des letzten Commits, den Du ändern möchtest, angeben. Bei drei Commit-Nachrichten müsste das Argument also `HEAD~2^` beziehungsweise `HEAD~3` lauten. Wahrscheinlich fällt es Dir leichter das Argument `~3` zu merken, weil Du ja schließlich auf die letzten drei Einträge verweisen möchtest. Du solltest Dir aber bewusst sein, dass Du auf den viertältesten Commit verweisen musst, also den übergeordneten Commit, den Du ändern möchtest. $ git rebase -i HEAD~3 -Es ist wichtig, dass Du Dir bewusst bist, dass mit diesem Rebase Befehl jeder Commit im Bereich `HEAD~3..HEAD` geändert wird, unabhängig davon, ob Du die Commit-Nachricht beziehungsweise den Schnappschuss änderst oder nicht. Der Rebase-Befehl sollte nie einen Commit beinhalten, der bereits an einen zentralen Server gepusht worden ist. -Hälst Du Dich nicht daran, werden sich andere Entwickler über Dich ärgern oder wundern, weil es jetzt eine alternative Version von der gleichen Änderung gibt. +Es ist wichtig, dass Du Dir bewusst bist, dass mit diesem Rebase-Befehl jeder Commit im Bereich `HEAD~3..HEAD` geändert wird, unabhängig davon, ob Du die Commit-Nachricht beziehungsweise den Schnappschuss änderst oder nicht. Der Rebase-Befehl sollte nie einen Commit beinhalten, der bereits an einen zentralen Server gepusht worden ist. +Hältst Du Dich nicht daran, werden sich andere Entwickler über Dich ärgern oder wundern, weil es jetzt eine alternative Version der gleichen Änderung gibt. -Wenn Du den Befehl ausführst, erhälst Du eine Reihe von Commits in Deinem Texteditor. Das könnte in etwa folgendermaßen aussehen: +Wenn Du den Befehl ausführst, erhältst Du eine Reihe von Commits in Deinem Texteditor. Das könnte in etwa folgendermaßen aussehen: pick f7f3f6d changed my name a bit pick 310154e updated README formatting and added blame @@ -774,7 +774,7 @@ Vielleicht ist es Dir schon aufgefallen, die Commits werden genau in der umgekeh -Siehst Du den Unterschied? Es ist genau die umgekehrte Reihenfolge. Ein interaktiver Rebase wird nach einem festen Schema, einer Art Skript, durchgeführt und der Texteditor zeigt Dir an, wie dieses Skript genau ablaufen wird. Der Rebase startet bei dem Commit der in der Kommandozeile angegeben wird (`HEAD~3`) und führt die Änderungen, die durch jeden Commit hinzukommen, von oben nach unten aus. Das bedeteutet, dass anstatt dem neuesten, der älteste Commit ganz oben steht, weil dieser der erste Commit ist, der bearbeitet wird. +Siehst Du den Unterschied? Es ist genau die umgekehrte Reihenfolge. Ein interaktiver Rebase wird nach einem festen Schema, einer Art Skript, durchgeführt und der Texteditor zeigt Dir an, wie dieses Skript genau ablaufen wird. Der Rebase startet bei dem Commit, der in der Kommandozeile angegeben wird (`HEAD~3`) und führt die Änderungen, die durch jeden Commit hinzukommen, von oben nach unten aus. Das bedeutet, dass anstatt des neuesten, der älteste Commit ganz oben steht, weil dieser der erste Commit ist, der bearbeitet wird. @@ -786,7 +786,7 @@ Du musst das Skript so anpassen, dass es an jedem Commit anhält, den Du ändern -Nachdem Du das Skript gespeichert und den Editor beendet hast, setzt Git nun alle Änderungen bis zum letzten Commit der Liste zurück und zeigt danach in der Kommandozeile in etwa folgendes an: +Nachdem Du das Skript gespeichert und den Editor beendet hast, setzt Git nun alle Änderungen bis zum letzten Commit der Liste zurück und zeigt danach in der Kommandozeile in etwa Folgendes an: $ git rebase -i HEAD~3 Stopped at 7482e0d... updated the gemspec to hopefully work better @@ -812,7 +812,7 @@ Im sich öffnenden Texteditor kannst Du jetzt die Commit-Nachricht ändern und d -Der letzte Befehl speichert die letzten beiden Commits automatisch im Repository und der Rebase ist danach abgeschlossen. Wenn Du in einer weiteren Zeile „pick“ mit „edit“ ersetzt hast, kannst Du die oben dargestellten Schritte entsprechend noch einmal ausführen. Git wird nach jedem Commit anhalten und Dir die Möglichkeit bieten, den Commit anzupassen. Danach kannst Du Git auffordern den Rebase fortzusetzen (`git rebase --continue`). +Der letzte Befehl speichert die letzten beiden Commits automatisch im Repository und der Rebase ist danach abgeschlossen. Wenn Du in einer weiteren Zeile „pick“ mit „edit“ ersetzt hast, kannst Du die oben dargestellten Schritte entsprechend noch einmal ausführen. Git wird nach jedem Commit anhalten und Dir die Möglichkeit bieten, den Commit anzupassen. Danach kannst Du Git auffordern, den Rebase fortzusetzen (`git rebase --continue`). ### Reihenfolge von Commits verändern ### @@ -855,7 +855,7 @@ Man kann mit einem interaktiven Rebase auch mehrere Commits zu einem einzelnen C -Wenn Du statt „pick“ oder „edit“, den Befehl „squash“ angibst, führt Git beide Commits zu einem gemeinsamen Commit zusammen und bietet Dir die Möglichkeit die Commit-Nachricht ebenso entsprechend zu verheiraten. Wenn Du also aus den drei Commits einen einzelnen Commit machen willst, muss Dein Skript folgendermaßen aufgebaut sein: +Wenn Du statt „pick“ oder „edit“, den Befehl „squash“ angibst, führt Git beide Commits zu einem gemeinsamen Commit zusammen und bietet Dir die Möglichkeit, die Commit-Nachricht ebenso entsprechend zu verheiraten. Wenn Du also aus den drei Commits einen einzelnen Commit machen willst, muss Dein Skript folgendermaßen aufgebaut sein: pick f7f3f6d changed my name a bit squash 310154e updated README formatting and added blame @@ -863,7 +863,7 @@ Wenn Du statt „pick“ oder „edit“, den Befehl „squash“ angibst, führ -Nach dem Speichern und Beenden des Editor, führt Git alle drei Änderungen zu einem einzelnen Commit zusammen und öffnet einen Texteditor, der alle drei Commit-Nachrichten enthält: +Nach dem Speichern und Beenden des Editors, führt Git alle drei Änderungen zu einem einzelnen Commit zusammen und öffnet einen Texteditor, der alle drei Commit-Nachrichten enthält: # This is a combination of 3 commits. @@ -887,7 +887,7 @@ Du kannst nun die Commit-Nachricht entsprechend anpassen oder auch entsprechend -Man kann mit Git einen einzelnen Commit auch aufsplitten. Das bedeutet, man setzt den ursprünglichen Commit zurück, fügt dann einen Teil der Änderungen zur Staging Area hinzu und checkt das Ergebnis ein. Dies kann man unbegrenzt oft wiederholen und so einen einzelnen Commit in mehrere Commits aufteilen. Nehmen wir an, wir möchten den mittleren der beiden Commits aufteilen. Anstatt „updated README formatting and added blame“, möchten wir den Commit in folgende beiden Commits aufteilen: „updated README formatting“ soll das Thema des ersten Commits und „added blame“ soll das Thema des zweiten Commits sein. Dazu kannst Du das angezeigt Skript, welches Dir der Befehl `rebase -i` erzeugt, folgendermaßen anpassen: +Man kann mit Git einen einzelnen Commit auch aufsplitten. Das bedeutet, man setzt den ursprünglichen Commit zurück, fügt dann einen Teil der Änderungen zur Staging-Area hinzu und checkt das Ergebnis ein. Dies kann man unbegrenzt oft wiederholen und so einen einzelnen Commit in mehrere Commits aufteilen. Nehmen wir an, wir möchten den mittleren der beiden Commits aufteilen. Anstatt „updated README formatting and added blame“, möchten wir den Commit in folgende beiden Commits aufteilen: „updated README formatting“ soll das Thema des ersten Commits und „added blame“ soll das Thema des zweiten Commits sein. Dazu kannst Du das angezeigte Skript, welches Dir der Befehl `rebase -i` erzeugt, folgendermaßen anpassen: pick f7f3f6d changed my name a bit edit 310154e updated README formatting and added blame @@ -895,7 +895,7 @@ Man kann mit Git einen einzelnen Commit auch aufsplitten. Das bedeutet, man setz -Nach dem Speichern und Schließen des Editors, setzt Git die Änderungen entsprechend zurück und wendet den ersten (`f7f3f6d`) und zweiten (`310154e`) Commit an und wechselt danach zurück zur Kommandozeile. Jetzt hast Du die Möglichkeit den letzten Commit zurückzusetzen, ohne das die Änderungen im Arbeitsverzeichnis zurückgesetzt werden. Das heißt, der Commit im Repository werden gelöscht, aber Deine Änderungen im Arbeitsverzeichnis gehen nicht verloren. Um dies durchzuführen, kannst Du den Befehl `git reset HEAD^` verwenden. Jetzt kannst Du die gewünschten Änderungen für den ersten Commit zur Staging Area hinzufügen und danach einchecken. Diesen Vorgang kannst Du beliebig wiederholen, bis alle Änderungen eingecheckt sind. Wenn Du fertig bist, kannst Du den Rebase mit `git rebase --continue` fortsetzen beziehungsweise abschließen: +Nach dem Speichern und Schließen des Editors, setzt Git die Änderungen entsprechend zurück und wendet den ersten (`f7f3f6d`) und zweiten (`310154e`) Commit an und wechselt danach zurück zur Kommandozeile. Jetzt hast Du die Möglichkeit den letzten Commit zurückzusetzen, ohne dass die Änderungen im Arbeitsverzeichnis zurückgesetzt werden. Das heißt, der Commit im Repository wird gelöscht, aber Deine Änderungen im Arbeitsverzeichnis gehen nicht verloren. Um dies durchzuführen, kannst Du den Befehl `git reset HEAD^` verwenden. Jetzt kannst Du die gewünschten Änderungen für den ersten Commit zur Staging-Area hinzufügen und danach einchecken. Diesen Vorgang kannst Du beliebig wiederholen, bis alle Änderungen eingecheckt sind. Wenn Du fertig bist, kannst Du den Rebase mit `git rebase --continue` fortsetzen beziehungsweise abschließen: $ git reset HEAD^ $ git add README @@ -906,7 +906,7 @@ Nach dem Speichern und Schließen des Editors, setzt Git die Änderungen entspre -Git speichert dazu den letzten Commit (`a5f4a0d`) aus dem Skript im Repository. Das Resultet sieht in etwa folgendermaßen aus: +Git speichert dazu den letzten Commit (`a5f4a0d`) aus dem Skript im Repository. Das Resultat sieht in etwa folgendermaßen aus: $ git log -4 --pretty=format:"%h %s" 1c002dd added cat-file @@ -916,21 +916,21 @@ Git speichert dazu den letzten Commit (`a5f4a0d`) aus dem Skript im Repository. -Ich möchte Dich noch einmal darauf hinweisen, dass jede SHA Prüfsumme von allen Commits au der Liste geändert werden. Bitte stell also sicher, dass diese Commits in keinem öffentlichen Repository verfügbar sind. +Ich möchte Dich noch einmal darauf hinweisen, dass jede SHA-Prüfsumme von allen Commits aus der Liste geändert werden. Bitte stell also sicher, dass diese Commits in keinem öffentlichen Repository verfügbar sind. ### Hol den Vorschlaghammer raus: filter-branch ### -Es gibt noch eine weitere Möglichkeit, wie man die Historie nach seinen Wünschen anpassen kann. Diese wird oft angewandt, wenn man eine große Zahl von Commits automatisiert mit Hilfe eines Skripts anpassen will. Zum Beispiel, kann man damit die E-Mail Adresse in jedem Commit ändern oder auch eine Datei aus jedem Commit entfernen. Das Werkzeug dazu heißt `filter-branch`. Damit kann man einen riesigen Teil der Historie ändern. Man sollte diesen Befehl also nur verwenden, wenn das Projekt noch nicht weit verbreitet ist, oder andere Personen noch nicht damit begonnen haben an dem Projekt zu Arbeiten (also auf Basis der bisherigen Historie neue Branches mit Commits erstellt). Trotzdem kann dieses Werkzeug sehr nützlich sein. Ich möchte hier ein paar der Möglichkeiten dieses Werkzeugs vorstellen. +Es gibt noch eine weitere Möglichkeit, wie man die Historie nach seinen Wünschen anpassen kann. Diese wird oft angewandt, wenn man eine große Zahl von Commits automatisiert mit Hilfe eines Skripts anpassen will. Zum Beispiel kann man damit die E-Mail-Adresse in jedem Commit ändern oder auch eine Datei aus jedem Commit entfernen. Das Werkzeug dazu heißt `filter-branch`. Damit kann man einen riesigen Teil der Historie ändern. Man sollte diesen Befehl also nur verwenden, wenn das Projekt noch nicht weit verbreitet ist, oder andere Personen noch nicht damit begonnen haben an dem Projekt zu arbeiten (also auf Basis der bisherigen Historie neue Branches mit Commits erstellt wurden). Trotzdem kann dieses Werkzeug sehr nützlich sein. Ich möchte hier ein paar der Möglichkeiten dieses Werkzeugs vorstellen. #### Löschen einer Datei aus jedem Commit #### -Dieses Szenario tritt sogar relativ häufig auf. Nehmen wir einmal an, jemand fügt gedankenlos eine große binäre Datei mit `git add .` zum Repository dazu und diese soll aber in keinem der Commits enthalten sein. Oder Du hast aus Versehen eine Datei, welche ein Passwort enthält, zum Repository hinzugefügt und möchtest dieses Repository nun veröffentlichen. `filter-branch` ist dann das Werkzeug Deiner Wahl um die komplette Historie umzukrempeln. Um eine Datei mit dem Namen „passwords.txt“ aus der kompletten Historie zu löschen, kannst Du die Option `--tree-filter` verwenden: +Dieses Szenario tritt sogar relativ häufig auf. Nehmen wir einmal an, jemand fügt gedankenlos eine große binäre Datei mit `git add .` zum Repository dazu und diese soll aber in keinem der Commits enthalten sein. Oder Du hast aus Versehen eine Datei, welche ein Passwort enthält, zum Repository hinzugefügt und möchtest dieses Repository nun veröffentlichen. `filter-branch` ist dann das Werkzeug Deiner Wahl, um die komplette Historie umzukrempeln. Um eine Datei mit dem Namen „passwords.txt“ aus der kompletten Historie zu löschen, kannst Du die Option `--tree-filter` verwenden: $ git filter-branch --tree-filter 'rm -f passwords.txt' HEAD Rewrite 6b9b3cf04e7c5686a9cb838c3f36a8cb6a0fc2bd (21/21) @@ -938,18 +938,18 @@ Dieses Szenario tritt sogar relativ häufig auf. Nehmen wir einmal an, jemand f -Die Option `--tree-filer` führt den nachfolgenden Befehl nach jedem Auschecken eines Commits des Projekts aus und checkt danach das Ergebnis wieder ein. In diesem Beispiel, wird die Datei „passwords.txt“ aus jedem Schnappschuss entfernt, unabhängig davon, ob sie existiert oder nicht. Ein anderes Beispiel wäre es, alle Backup-Dateien eines Texteditors aus dem Repository zu löschen. Dazu kann man in etwa den Befehl `git filter-branch -\-tree-filter "rm -f *~" HEAD` ausführen. +Die Option `--tree-filer` führt den nachfolgenden Befehl nach jedem Auschecken eines Commits des Projekts aus und checkt danach das Ergebnis wieder ein. In diesem Beispiel wird die Datei „passwords.txt“ aus jedem Schnappschuss entfernt, unabhängig davon, ob sie existiert oder nicht. Ein anderes Beispiel wäre es, alle Backup-Dateien eines Texteditors aus dem Repository zu löschen. Dazu kann man in etwa den Befehl `git filter-branch -\-tree-filter "rm -f *~" HEAD` ausführen. -Git informiert Dich über den Fortschritt dieses Vorgangs und Du siehst, wie jeder Commit angepasst wird und der Zeiger auf den Branch auf den letzten Commit gesetzt wird. Es ist empfehlenswert, diesen Befehl in einem Testzweig durchzuführen. Wenn das Ergebnis, wie gewünscht ausfällt, kann man danach den Master Branch auf diesen Testzweig setzen. Wenn man an den Befehl `filter-branch` die Option `--all` anfügt, führt Git diesen Vorgang für jeden vorhandenen Zweig aus. +Git informiert Dich über den Fortschritt dieses Vorgangs und Du siehst, wie jeder Commit angepasst wird und der Zeiger auf den Branch auf den letzten Commit gesetzt wird. Es ist empfehlenswert, diesen Befehl in einem Testzweig durchzuführen. Wenn das Ergebnis, wie gewünscht ausfällt, kann man danach den Branch master auf diesen Testzweig setzen. Wenn man an den Befehl `filter-branch` die Option `--all` anfügt, führt Git diesen Vorgang für jeden vorhandenen Zweig aus. #### Aus einem Unterverzeichnis das neue Wurzelverzeichnis machen #### -Wenn man zum Beispiel ein Projekt aus einem anderen Versionskontrollwerkzeug in Git importiert, gibt es dort oft Verzeichnisse, die in Git nicht relevant sind, zum Beispiel trunk, tags, usw.. Wenn man also das Unterverzeichnis „trunk“ das neue Wurzelverzeichnis machen will, kann man dies mit Hilfe von `filter-branch` umsetzen: +Wenn man zum Beispiel ein Projekt aus einem anderen Versionskontrollwerkzeug in Git importiert, gibt es dort oft Verzeichnisse, die in Git nicht relevant sind, zum Beispiel trunk, tags, usw.. Wenn man also das Unterverzeichnis `trunk` das neue Wurzelverzeichnis machen will, kann man dies mit Hilfe von `filter-branch` umsetzen: $ git filter-branch --subdirectory-filter trunk HEAD Rewrite 856f0bf61e41a27326cdae8f09fe708d679f596f (12/12) @@ -964,7 +964,7 @@ Nach der Ausführung dieses Befehls ist das „trunk“ Verzeichnis das neue Arb -Verflixt, es ist schon wieder passiert. Du hast vergessen den Befehl `git config` auszuführen und Deinen Namen und E-Mail Adresse zu setzen bevor Du mit der Arbeit begonnen hast. Mit `filter-branch` kann man diesen Fehler einfach beheben. Man sollte nur darauf achten, dass man nur seine eigene E-Mail Adresse ändert. Deshalb verwenden wir die Option `--commit-filter`: +Verflixt, es ist schon wieder passiert. Du hast vergessen, den Befehl `git config` auszuführen und Deinen Namen und E-Mail-Adresse zu setzen, bevor Du mit der Arbeit begonnen hast. Mit `filter-branch` kann man diesen Fehler einfach beheben. Man sollte nur darauf achten, dass man nur seine eigene E-Mail-Adresse ändert. Deshalb verwenden wir die Option `--commit-filter`: $ git filter-branch --commit-filter ' if [ "$GIT_AUTHOR_EMAIL" = "schacon@localhost" ]; @@ -978,7 +978,7 @@ Verflixt, es ist schon wieder passiert. Du hast vergessen den Befehl `git config -Dieser Befehl durchforstet das Repository und ersetzt in jedem Commit, dessen E-Mail Adresse des Autors „schacon@localhost“ lautet, mit der neuen E-Mail Adresse „schacon@example.com“. Zusätzlich wir der Name des Autors geändert, falls dieser nicht vorher schon „Scott Chacon“ war. Auf Grund der Architektur, dass in Git in jedem Commit die SHA1 Prüfsumme des Vorgänger Commits enthalten ist, ändert dieser Befehl jeden Commit in Deiner Historie. Die SHA1 Prüfsumme wird sich auch in allen Commits, die nicht die angegebene E-Mail Adresse enthalten, verändern. +Dieser Befehl durchforstet das Repository und ersetzt in jedem Commit, dessen E-Mail-Adresse des Autors „schacon@localhost“ lautet, mit der neuen E-Mail-Adresse „schacon@example.com“. Zusätzlich wird der Name des Autors geändert, falls dieser nicht vorher schon „Scott Chacon“ war. Auf Grund der Architektur, dass in Git in jedem Commit die SHA1-Prüfsumme des Vorgänger-Commits enthalten ist, ändert dieser Befehl jeden Commit in Deiner Historie. Die SHA1-Prüfsumme wird sich auch in allen Commits, die nicht die angegebene E-Mail-Adresse enthalten, verändern. ## Mit Hilfe von Git debuggen ## @@ -992,7 +992,7 @@ Git bietet auch ein paar Werkzeuge, die den Debug-Vorgang bei einem Projekt unte -Wenn Du nach einem Bug in Deinem Code suchst und gerne wissen willst, wann und warum dieser zum ersten mal auftrat, dann kann Dir das Werkzeug Datei Annotation (engl. File Annotation) sicher weiterhelfen. Es kann Dir anzeigen, in welchem Commit die jeweilige Zeile einer Datei zuletzt geändert wurde. Wenn Du also feststellst, dass eine Methode beziehungsweise eine Funktion in Deinem Code nicht mehr das gewünschte Resultat liefert, kannst Du Dir die Datei mit `git blame` genauer ansehen. Nach Aufruf des Befehls zeigt Git Dir an, welche Zeile von welcher Person als letztes geändert wurde, inklusive Datum. Das folgende Beispiel verwendet die Option `-L` um die Ausgabe auf die Zeilen 12 bis 22 einzuschränken: +Wenn Du nach einem Bug in Deinem Code suchst und gerne wissen willst, wann und warum dieser zum ersten Mal auftrat, dann kann Dir das Werkzeug Datei-Annotation (engl. File Annotation) sicher weiterhelfen. Es kann Dir anzeigen, in welchem Commit die jeweilige Zeile einer Datei zuletzt geändert wurde. Wenn Du also feststellst, dass eine Methode beziehungsweise eine Funktion in Deinem Code nicht mehr das gewünschte Resultat liefert, kannst Du Dir die Datei mit `git blame` genauer ansehen. Nach Aufruf des Befehls zeigt Git Dir an, welche Zeile von welcher Person als letztes geändert wurde, inklusive Datum. Das folgende Beispiel verwendet die Option `-L`, um die Ausgabe auf die Zeilen 12 bis 22 einzuschränken: $ git blame -L 12,22 simplegit.rb ^4832fe2 (Scott Chacon 2008-03-15 10:31:28 -0700 12) def show(tree = 'master') @@ -1009,11 +1009,11 @@ Wenn Du nach einem Bug in Deinem Code suchst und gerne wissen willst, wann und w -In der ersten Spalte wird die Kurzform der SHA1 Prüfsumme des Commits angezeigt, in welchem diese Zeile zuletzt verändert wurde. Die nächsten beiden Spalten weisen auf den Autor des Commits und wann dieser verfasst wurde, hin. Auf diese Weise kannst Du leicht bestimmen, wer die jeweilige Zeile geändert hat und wann dies durchgeführt wurde. In den nächsten Spalten wird die Zeilennummer und der Inhalt der Zeile angezeigt. Die Zeilen mit der SHA1 Prüfsumme `^4832fe2` weisen darauf hin, dass diese bereits im ersten Commit vorhanden waren. Das ist also der Commit, in dem die Datei „simplegit.rb“ zum Repository hinzugefügt wurde und die Zeilen deuten damit darauf hin, dass diese bisher nie geändert wurden. Das ist für Dich wahrscheinlich ein bisschen verwirrend, denn nun kennst Du bereits drei Möglichkeiten, wie Git mit dem Zeichen `^` einer SHA1 Prüfsumme eine neue Bedeutung gibt. Aber in Zusammenhang mit `git blame` weist das Zeichen auf den eben geschilderten Sachverhalt hin. +In der ersten Spalte wird die Kurzform der SHA1-Prüfsumme des Commits angezeigt, in welchem diese Zeile zuletzt verändert wurde. Die nächsten beiden Spalten weisen auf den Autor des Commits und wann dieser verfasst wurde, hin. Auf diese Weise kannst Du leicht bestimmen, wer die jeweilige Zeile geändert hat und wann dies durchgeführt wurde. In den nächsten Spalten wird die Zeilennummer und der Inhalt der Zeile angezeigt. Die Zeilen mit der SHA-1-Prüfsumme `^4832fe2` weisen darauf hin, dass diese bereits im ersten Commit vorhanden waren. Das ist also der Commit, in dem die Datei „simplegit.rb“ zum Repository hinzugefügt wurde und die Zeilen deuten damit darauf hin, dass diese bisher nie geändert wurden. Das ist für Dich wahrscheinlich ein bisschen verwirrend, denn nun kennst Du bereits drei Möglichkeiten, wie Git mit dem Zeichen `^` einer SHA-Prüfsumme eine neue Bedeutung gibt. Aber in Zusammenhang mit `git blame` weist das Zeichen auf den eben geschilderten Sachverhalt hin. -Eine weitere herausragende Eigenschaft von Git ist die Tatsache, dass es nicht per se das Umbenennen von Dateien verfolgt. Git speichert immer den jeweiligen Schnappschuss des Dateisystems und versucht erst danach zu bestimmen, welche Dateien umbenannt wurden. Das bietet Dir zum Beispiel die Möglichkeit herauszufinden, wie Code innerhalb des Repositorys hin und her verschoben wurde. Wenn Du also die Option `-C` an `git blame` anfügst, analysiert Git die angebene Datei und versucht herauszufinden, ob und von wo bestimmte Codezeilen herkopiert wurden. Vor kurzem habe ich ein Refactoring an einer Datei mit dem Namen `GITServerHandler.m` durchgeführt. Dabei habe ich diese Datei in mehrere Dateien aufgteilt, eine davon war `GITPackUpload.m`. Wenn ich jetzt `git blame` mit der Option `-C` auf die Datei `GITPackUpload.m` ausführe, erhalte ich eine Ausgabe mit den Codezeilen von denen das Ergebnis ursprünglich stammt: +Eine weitere herausragende Eigenschaft von Git ist die Tatsache, dass es nicht per se das Umbenennen von Dateien verfolgt. Git speichert immer den jeweiligen Schnappschuss des Dateisystems und versucht erst danach zu bestimmen, welche Dateien umbenannt wurden. Das bietet Dir zum Beispiel die Möglichkeit herauszufinden, wie Code innerhalb des Repositorys hin und her verschoben wurde. Wenn Du also die Option `-C` an `git blame` anfügst, analysiert Git die angegebene Datei und versucht herauszufinden, ob und von wo bestimmte Codezeilen herkopiert wurden. Vor kurzem habe ich ein Refactoring an einer Datei mit dem Namen `GITServerHandler.m` durchgeführt. Dabei habe ich diese Datei in mehrere Dateien aufgeteilt, eine davon war `GITPackUpload.m`. Wenn ich jetzt `git blame` mit der Option `-C` auf die Datei `GITPackUpload.m` ausführe, erhalte ich eine Ausgabe mit den Codezeilen, von denen das Ergebnis ursprünglich stammt: $ git blame -C -L 141,153 GITPackUpload.m f344f58d GITServerHandler.m (Scott 2009-01-04 141) @@ -1032,18 +1032,18 @@ Eine weitere herausragende Eigenschaft von Git ist die Tatsache, dass es nicht p -Das ist enorm hilfreich. Für gewöhnlich erhälst Du damit als ursprünglichen Commit, den Commit, von welchem der Code kopiert wurde, da dies der Zeitpunkt war, bei dem diese Zeilen zum ersten mal angefasst wurden. Git zeigt Dir den ursprünglichen Commit, in dem Du die Zeilen verfasst hast, sogar an, wenn es sich dabei um eine andere Datei handelt. +Das ist enorm hilfreich. Für gewöhnlich erhältst Du damit als ursprünglichen Commit, den Commit, von welchem der Code kopiert wurde, da dies der Zeitpunkt war, bei dem diese Zeilen zum ersten Mal angefasst wurden. Git zeigt Dir den ursprünglichen Commit, in dem Du die Zeilen verfasst hast, sogar an, wenn es sich dabei um eine andere Datei handelt. ### Das Bisect Werkzeug – Binäre Suche### -`git blame` kann Dir sehr weiterhelfen, wenn Du bereits weißt, an welcher Stelle das Problem liegt. Wenn Du aber nicht weißt, warum gewisse Dinge schief laufen, und es gibt inzwischen dutzende oder hunderte von Commits seit dem letzten funktionierenden Stand, dann solltest Du `git bisect` als Hilfestellung verwenden. Der `bisect` Befehl führt eine binäre Suche durch die Commit-Historie durch und hilft Dir auf schnelle Art und Weise die Commits zu bestimmen, die eventuell für das Problem verantwortlich sind. +`git blame` kann Dir sehr weiterhelfen, wenn Du bereits weißt, an welcher Stelle das Problem liegt. Wenn Du aber nicht weißt, warum gewisse Dinge schief laufen, und es gibt inzwischen Dutzende oder Hunderte von Commits seit dem letzten funktionierenden Stand, dann solltest Du `git bisect` als Hilfestellung verwenden. Der `bisect` Befehl führt eine binäre Suche durch die Commit-Historie durch und hilft Dir auf schnelle Art und Weise die Commits zu bestimmen, die eventuell für das Problem verantwortlich sind. -Nehmen wir zum Beispiel an, dass Du gerade eben Deinen Code in einer Produktivumgebung veröffentlicht hast und auf einmal bekommst Du zahlreiche Fehlerberichte über Probleme, die in Deiner Entwicklungsumgebung nicht aufgetreten sind. Du kannst Dir auch keinen Reim darauf bilden, warum der Code so reagiert. Nachdem Du Dich noch einmal näher mit Deinem Code beschäftigt hast, stellst Du fest, dass Du die Fehlerwirkung reproduzieren kannst, aber Dir ist es immer noch ein Rätsel was genau schief läuft. Wenn Du vor einem solchen Problem stehst, hilft Dir es bestimmt, wenn Du die Historie in mehrere Teile aufspaltest (engl. bisect: halbieren, zweiteilen). Als erstes startest Du mit dem Befehl `git bisect start`. Danach gibst Du mit dem Befehl `git bisect bad` an, dass der derzeit ausgecheckte Commit den Fehler aufweist. Jetzt braucht Git noch die Information, in welchem Commit das Problem noch nicht aufgetreten ist. Dazu verwendest Du den Befehl `git bisect good [good_commit]`: +Nehmen wir zum Beispiel an, dass Du gerade eben Deinen Code in einer Produktivumgebung veröffentlicht hast und auf einmal bekommst Du zahlreiche Fehlerberichte über Probleme, die in Deiner Entwicklungsumgebung nicht aufgetreten sind. Du kannst Dir auch keinen Reim darauf bilden, warum der Code so reagiert. Nachdem Du Dich noch einmal näher mit Deinem Code beschäftigt hast, stellst Du fest, dass Du die Fehlerwirkung reproduzieren kannst, aber Dir ist es immer noch ein Rätsel, was genau schief läuft. Wenn Du vor einem solchen Problem stehst, hilft Dir es bestimmt, wenn Du die Historie in mehrere Teile aufspaltest (engl. bisect: halbieren, zweiteilen). Als erstes startest Du mit dem Befehl `git bisect start`. Danach gibst Du mit dem Befehl `git bisect bad` an, dass der derzeit ausgecheckte Commit den Fehler aufweist. Jetzt braucht Git noch die Information, in welchem Commit das Problem noch nicht aufgetreten ist. Dazu verwendest Du den Befehl `git bisect good [good_commit]`: $ git bisect start $ git bisect bad @@ -1053,7 +1053,7 @@ Nehmen wir zum Beispiel an, dass Du gerade eben Deinen Code in einer Produktivum -Nach Ausführen des letzten Befehls, zeigt Git Dir als erstes an, dass in etwa 12 Commits zwischen der letzten guten Revision (v1.0) und der aktuellen, fehlerhaften Revision liegen. Auf Basis dieser Information hat Git Dir den mittleren Commit ausgecheckt. Jetzt hast Du die Möglichkeit Deine Tests auf Basis des ausgecheckten Stands durchzuführen um herauszufinden, ob in diesem Commit der Fehler bereits bestand. Wenn der Fehler hier bereits auftritt, dann wurde er in diesem oder in einem der früheren Commits eingefügt. Wenn der Fehler hier noch nicht auftritt, dann wurde er in einem der späteren Commits eingeschleppt. In unserem Beispiel nehmen wir an, dass in diesem Commit der Fehler noch nicht bestand. Das geben wir mit dem Befehl `git bisect good` an und fahren fort: +Nach Ausführen des letzten Befehls, zeigt Git Dir als Erstes an, dass in etwa 12 Commits zwischen der letzten guten Revision (v1.0) und der aktuellen, fehlerhaften Revision liegen. Auf Basis dieser Information hat Git Dir den mittleren Commit ausgecheckt. Jetzt hast Du die Möglichkeit Deine Tests auf Basis des ausgecheckten Stands durchzuführen, um herauszufinden, ob in diesem Commit der Fehler bereits bestand. Wenn der Fehler hier bereits auftritt, dann wurde er in diesem oder in einem der früheren Commits eingefügt. Wenn der Fehler hier noch nicht auftritt, dann wurde er in einem der späteren Commits eingeschleppt. In unserem Beispiel nehmen wir an, dass in diesem Commit der Fehler noch nicht bestand. Das geben wir mit dem Befehl `git bisect good` an und fahren fort: $ git bisect good Bisecting: 3 revisions left to test after this @@ -1061,7 +1061,7 @@ Nach Ausführen des letzten Befehls, zeigt Git Dir als erstes an, dass in etwa 1 -Git hat Dir jetzt einen weiteren Commit ausgecheckt und zwar wieder den mittleren Commit zwischen dem letzten Stand im Repository und dem mittleren Commit aus der letzten Runde. Hier nehmen wir an, dass Du nach Deinen durchgeführten Tests feststellst, dass in diesem Commit der Fehler bereits vorhanden ist. Das müssen wir Git über `git bisect bad` mitteilen: +Git hat Dir jetzt einen weiteren Commit ausgecheckt, und zwar wieder den mittleren Commit zwischen dem letzten Stand im Repository und dem mittleren Commit aus der letzten Runde. Hier nehmen wir an, dass Du nach Deinen durchgeführten Tests feststellst, dass in diesem Commit der Fehler bereits vorhanden ist. Das müssen wir Git über `git bisect bad` mitteilen: $ git bisect bad Bisecting: 1 revisions left to test after this @@ -1069,7 +1069,7 @@ Git hat Dir jetzt einen weiteren Commit ausgecheckt und zwar wieder den mittlere -Git checkt wieder den nächsten mittleren Commit aus und wir stellen fest, dass dieser in Ordnung ist. Ab jetzt hat Git alle notwendigen Informationen um festzustellen, in welchem Commit der Fehler eingebaut wurde. Git zeigt Dir dazu die SHA1 Prüfsumme des ersten fehlerhaften Commits an. Zusätzlich gibt es noch weitere Commit Informationen und welche Dateien in diesem Commit geändert wurden, an. Das sollte Dir nun helfen, den Fehler näher zu bestimmen: +Git checkt wieder den nächsten mittleren Commit aus und wir stellen fest, dass dieser in Ordnung ist. Ab jetzt hat Git alle notwendigen Informationen um festzustellen, in welchem Commit der Fehler eingebaut wurde. Git zeigt Dir dazu die SHA-1-Prüfsumme des ersten fehlerhaften Commits an. Zusätzlich gibt es noch weitere Commit-Informationen und welche Dateien in diesem Commit geändert wurden, an. Das sollte Dir nun helfen, den Fehler näher zu bestimmen: $ git bisect good b047b02ea83310a70fd603dc8cd7a6cd13d15c04 is first bad commit @@ -1090,28 +1090,37 @@ Wenn Du fertig mit der Fehlersuche bist, solltest Du den Befehl `git bisect rese -Wie Du vielleicht gesehen hast, ist dieser Befehl ein mächtiges Werkzeug um hunderte von Commit auf schnelle Art und Weise nach einem bestimmten Fehler zu durchsuchen. Besonders nützlich ist es, wenn Du ein Skript hast, welches mit dem Fehlercode Null beendet, wenn das Projekt in Ordnung ist und mit einem Fehlercode größer Null, wenn das Projekt Fehler enthält. Wenn Dir ein solches Skript zur Verfügung steht, kannst Du den bisher manuell durchgeführten Vorgang auch automatisieren. Wie im vorigen Beispiel musst Du Git den zuletzt fehlerfreien Commit und den fehlerhaften Commit angeben. Als verkürzte Schreibweise kannst Du an den Befehl `bisect start` den fehlerhaften und den fehlerfreien Commit angeben: +Wie Du vielleicht gesehen hast, ist dieser Befehl ein mächtiges Werkzeug, um Hunderte von Commits auf schnelle Art und Weise nach einem bestimmten Fehler zu durchsuchen. Besonders nützlich ist es, wenn Du ein Skript hast, welches mit dem Fehlercode Null beendet, wenn das Projekt in Ordnung ist und mit einem Fehlercode größer Null, wenn das Projekt Fehler enthält. Wenn Dir ein solches Skript zur Verfügung steht, kannst Du den bisher manuell durchgeführten Vorgang auch automatisieren. Wie im vorigen Beispiel musst Du Git den zuletzt fehlerfreien Commit und den fehlerhaften Commit angeben. Als verkürzte Schreibweise kannst Du an den Befehl `bisect start` den fehlerhaften und den fehlerfreien Commit angeben: $ git bisect start HEAD v1.0 $ git bisect run test-error.sh -Wenn Du die untere, genannte Zeile ausführst, führt Git automatisch nach jedem Auscheckvorgang das Skript `test-error.sh` aus und zwar solange bis es den Commit findet, der als erstes ein fehlerhaftes Ergebnis liefert. Statt einem Skript kannst Du natürlich auch `make` oder `make tests` oder eine beliebige, andere Testumgebung starten. +Wenn Du die untere, genannte Zeile ausführst, führt Git automatisch nach jedem Auscheckvorgang das Skript `test-error.sh` aus und zwar solange bis es den Commit findet, der als erstes ein fehlerhaftes Ergebnis liefert. Statt eines Skripts kannst Du natürlich auch `make` oder `make tests` oder eine beliebige, andere Testumgebung starten. ## Submodule ## +Oft möchte man während der Arbeit an einem Projekt ein weiteres Projekt darin einbinden und verwenden. Das kann zum Beispiel eine Bibliothek von einer anderen Firma oder vielleicht auch eine selbstentwickelte Bibliothek sein. In einem solchen Szenario tritt dann meistens folgendes Problem auf: Die zwei Projekte sollen unabhängig voneinander entwickelt werden können, aber trotzdem soll es möglich sein, das eine Projekt im anderen zu verwenden. + +Dazu ein Beispiel. Nehmen wir an, Du entwickelst gerade eine Webseite, die unter anderem einen Atom-Feed zur Verfügung stellen soll. Anstatt den notwendigen Code zur Auslieferung des Atom-Feeds selber zu schreiben, entscheidest Du Dich für eine geeignete Bibliothek. Dann wirst Du wahrscheinlich den Code in Dein Projekt einbinden müssen, zum Beispiel durch eine CPAN-Installation oder ein Ruby-Gem oder durch Kopieren des Quellcodes in das Arbeitsverzeichnis Deines Projekts. Das Problem beim Einbinden einer Bibliothek ist, dass es schwierig ist, diese an die eigene Bedürfnisse anzupassen. Noch schwieriger gestaltet sich dann die Veröffentlichung des Projekts, da man sicherstellen muss, dass jeder der die Software verwendet, auf die Bibliothek zugreifen kann. Wenn man die Bibliothek im eigenen Projekt projektspezifisch anpasst, hat man meist ein Problem, wenn man eine neue Version der Bibliothek einspielen will. + +Git löst dieses Problem mit Hilfe von Submodulen. Mit Hilfe von Submodulen kann man innerhalb eines Git-Repositorys ein weiteres Git-Repository in einem Unterverzeichnis verwalten. Daraus entsteht der Vorteil, dass man ein anderes Repository in das eigene Projekt klonen kann und die Commits der jeweiligen Projekte trennen kann. + +### Die ersten Schritte mit Submodulen ### +Nehmen wir einmal an, dass Du die Rack-Bibliothek (eine Ruby-Gateway-Schnittstelle für Webserver) zu Deinem Projekt hinzufügen willst. Dabei möchtest Du Deine eigenen Änderungen an dieser Bibliothek nachverfolgen, aber auch weiterhin Änderungen von den Rack-Bibliothek-Entwicklern verwalten und zusammenmergen. Das erste was Du dazu tun musst, ist das Repository der Rack Bibliothek in ein Unterverzeichnis Deines Projekts zu klonen. Diesen Vorgang kannst Du mit Hilfe des Befehls `git submodule add` ausführen: + $ git submodule add git://github.com/chneukirchen/rack.git rack Initialized empty Git repository in /opt/subtest/rack/.git/ remote: Counting objects: 3181, done. @@ -1122,6 +1131,8 @@ Wenn Du die untere, genannte Zeile ausführst, führt Git automatisch nach jedem +Innerhalb Deines Projekts befindet sich nun im Unterverzeichnis `rack` das komplette Rack-Projekt. Man kann jetzt in diesem Verzeichnis Änderungen vornehmen und ein eigenes Remote-Repository mit Schreibrechten, zu welchem man pushen kann, hinzufügen. Ebenso ist es möglich, Änderungen von den Rack-Entwicklern in sein Repository zu laden und diese mit den eigenen Ergebnissen zu mergen. Im Prinzip kann man innerhalb eines Submoduls die gleichen Vorgänge, wie in einem normalen Repository ausführen. Vorher müssen wir aber noch ein paar weitere Dinge zu Submodulen besprechen. Wenn Du gleich nach dem Hinzufügen des Submoduls, den Befehl `git status` ausführst, wirst Du gleich zwei Dinge bemerken: + $ git status # On branch master # Changes to be committed: @@ -1133,6 +1144,8 @@ Wenn Du die untere, genannte Zeile ausführst, führt Git automatisch nach jedem +Als erstes wird Dir die neue Datei `.gitmodules` auffallen. Das ist eine Konfigurationsdatei, welche die Zuordnung der URL des geklonten Projekts und dem lokalen Unterverzeichnis, in welches das Projekt geklont wurde, festlegt: + $ cat .gitmodules [submodule "rack"] path = rack @@ -1140,8 +1153,12 @@ Wenn Du die untere, genannte Zeile ausführst, führt Git automatisch nach jedem +Wenn Du mehrere Submodule in einem Projekt verwaltest, werden auch mehrere Einträge in dieser Datei auftauchen. Dabei ist es wichtig zu wissen, dass diese Datei zusammen mit all den anderen Dateien aus Deinem Projekt, ebenso in die Versionskontrolle aufgenommen wird, ähnlich wie die Datei `.gitignore`. Die Datei wird so wie der Rest Deines Projekts gepusht und gepullt. Dadurch wissen andere Personen, die Dein Projekt klonen, von welchem Ort sie die Submodule erhalten können. + +Die zweite Auffälligkeit bei der Ausgabe von `git status` ist der Eintrag rack. Wenn Du auf diesen Eintrag ein `git diff` durchführst, erhält man in etwa die folgende, interessante Ausgabe: + $ git diff --cached rack diff --git a/rack b/rack new file mode 160000 @@ -1153,10 +1170,16 @@ Wenn Du die untere, genannte Zeile ausführst, führt Git automatisch nach jedem +Obwohl `rack` ein Unterverzeichnis in Deinem Arbeitsverzeichnis ist, erkennt Git dieses Verzeichnis als Submodul und verfolgt die Änderungen innerhalb dieses Verzeichnisses nicht, wenn Git nicht innerhalb dieses Verzeichnisses aufgerufen wird. Stattdessen erfasst Git, welcher Commit in diesem Repository ausgecheckt ist. Wenn Du also Änderungen in diesem Unterverzeichnis durchführst und eincheckst, kann das Superprojekt erkennen, dass sich der aktuelle HEAD von diesem Projekt geändert hat. Das Superprojekt kann sich jetzt diesen Commit merken. Auf diese Art und Weise ist es möglich, den kompletten Zustand des Projekts mit allen Projekten, die als Submodul hinzugefügt wurden, zu reproduzieren. In der Git-Terminologie wird das Projekt, welches eines oder mehrere Submodule enthält, als Superprojekt bezeichnet. + +Dabei muss man sich folgender Eigenschaft bewusst sein: Git verwaltet den exakten Commit, der gerade ausgecheckt ist und nicht etwa den Branch oder eine andere Referenz. Git kann also zum Beispiel nicht speichern, dass der aktuelle Stand im Branch `master` enthalten ist. + +Wenn Du Dein Projekt das erste Mal eincheckst, erhältst Du in etwa folgende Ausgabe: + $ git commit -m 'first commit with submodule rack' [master 0550271] first commit with submodule rack 2 files changed, 4 insertions(+), 0 deletions(-) @@ -1165,8 +1188,12 @@ Wenn Du die untere, genannte Zeile ausführst, führt Git automatisch nach jedem +Der Mode 160000, der für den rack-Eintrag gilt, ist ein spezieller Mode in Git. Er bedeutet in etwa, dass man einen Commit als Verzeichnis-Eintrag in Git verwaltet und damit nicht wie normalerweise ein Verzeichnis oder eine Datei. + +Das Verzeichnis `rack` kann man wie ein separates Projekt behandeln und verwenden. Und von Zeit zur Zeit aktualisiert man auch das Superprojekt und speichert damit die letzte Commit-ID des Unterprojekts. Jedes Git-Kommando arbeitet unabhängig in einem der beiden Unterverzeichnisse: + $ git log -1 commit 0550271328a0038865aad6331e620cd7238601bb Author: Scott Chacon @@ -1182,9 +1209,12 @@ Wenn Du die untere, genannte Zeile ausführst, führt Git automatisch nach jedem Document version change +### Klonen eines Projekts mit den dazugehörigen Submodulen ### +Als nächstes klonen wir ein Projekt, welches ein Submodul verwendet. Wenn man ein solches Projekt klont, werden die entsprechenden Verzeichnisse, welche ein Submodul enthalten, erstellt. Allerdings enthalten diese Verzeichnisse noch keinen Inhalt: + $ git clone git://github.com/schacon/myproject.git Initialized empty Git repository in /opt/myproject/.git/ remote: Counting objects: 6, done. @@ -1201,6 +1231,8 @@ Wenn Du die untere, genannte Zeile ausführst, führt Git automatisch nach jedem +Das Verzeichnis `rack` wurde zwar erzeugt, aber es ist leer. Deshalb musst Du zwei Dinge ausführen: `git submodule init`, damit wird die Datei für die lokale Konfiguration initialisiert. Und `git submodule update`, welches die gesamten Daten des Projekts von der im `.gitmodules` angegebenen Quelle holt und den entsprechenden Commit, welcher im Superprojekt hinterlegt ist, auscheckt: + $ git submodule init Submodule 'rack' (git://github.com/chneukirchen/rack.git) registered for path 'rack' $ git submodule update @@ -1214,6 +1246,8 @@ Wenn Du die untere, genannte Zeile ausführst, führt Git automatisch nach jedem +Nach Ausführung der beiden Befehle befindet sich das Verzeichnis `rack` in genau dem gleichen Zustand, wie wir es ursprünglich eingecheckt haben. Wenn ein anderer Entwickler Änderungen am Rack-Code durchführt, diese eincheckt und Du diese dann pullst und mergst, erhält man einen etwas seltsamen Zustand: + $ git merge origin/master Updating 0550271..85a3eee Fast forward @@ -1230,6 +1264,8 @@ Wenn Du die untere, genannte Zeile ausführst, führt Git automatisch nach jedem +Der Merge, der gerade durchgeführt worden ist, ist eigentlich nur eine Aktualisierung des Zeigers auf einen neuen Commit des Submoduls. Der eigentliche Inhalt des Submodul-Verzeichnis wurde allerdings nicht aktualisiert. Das sieht dann so aus, als gäbe es noch nicht eingecheckte Dateien innerhalb Deines Arbeitsverzeichnis: + $ git diff diff --git a/rack b/rack index 6c5e70b..08d709f 160000 @@ -1241,6 +1277,8 @@ Wenn Du die untere, genannte Zeile ausführst, führt Git automatisch nach jedem +Dieser Zustand tritt auf, weil der Zeiger auf den Commit im Submodul derzeit nicht der Commit ist, welcher im Submodul ausgecheckt ist. Um dies zu beheben, muss man den Befehl `git submodule update` erneut ausführen: + $ git submodule update remote: Counting objects: 5, done. remote: Compressing objects: 100% (3/3), done. @@ -1252,14 +1290,20 @@ Wenn Du die untere, genannte Zeile ausführst, führt Git automatisch nach jedem +Dieser Update muss jedes Mal ausgeführt werden, wenn man das Superprojekt pullt und dort ein Änderung in einem Submodul enthalten ist. Es ist vielleicht ein wenig merkwürdig, aber es funktioniert. + +Häufig tritt beim Arbeiten mit Submodulen ein Problem bei folgendem Szenario auf: Ein Entwickler führt Änderungen in einem Submodul durch, checkt diese ein, vergisst aber diese Änderungen zum zentralen Server zu pushen. Wenn dann im Superprojekt die Änderung des Submoduls ebenso eingecheckt wird und dieses dann gepusht wird, tritt ein Problem auf. Wenn jetzt andere Entwickler den neuen Stand des Superprojekts holen und den Befehl `git submodule update` ausführen, erhalten sie eine Fehlermeldung, dass der entsprechend referenzierte Commit von dem Submodul nicht gefunden werden konnte. Das passiert weil dieser Commit bei dem zweiten Entwickler noch gar nicht existiert. Wenn ein solcher Fall auftritt, erhält man in etwa folgende Fehlermeldung: + $ git submodule update fatal: reference isn’t a tree: 6c5e70b984a60b3cecd395edd5b48a7575bf58e0 Unable to checkout '6c5e70b984a60b3cecd395edd5ba7575bf58e0' in submodule path 'rack' +Dann kann man allerdings herausfinden, wer zum letzten Mal eine Änderung eingecheckt hat: + $ git log -1 rack commit 85a3eee996800fcfa91e2119372dd4172bf76678 Author: Scott Chacon @@ -1269,20 +1313,34 @@ Wenn Du die untere, genannte Zeile ausführst, führt Git automatisch nach jedem +Dann kannst Du diesem Entwickler eine E-Mail schreiben und ihn auf seinen Fehler aufmerksam machen. + +### Superprojekte ### - +In manchen großen Projekten möchten die Entwickler die Arbeit in verschiedenen Verzeichnissen aufteilen, sodass das jeweilige Team in diesen Verzeichnissen arbeiten kann. Man trifft diese Vorgehensweise häufig an, wenn ein Team gerade von CVS oder Subversion nach Git gewechselt hat, im alten System ein Modul oder eine Sammlung von solchen Unterverzeichnissen gebildet hat und diesen Arbeitsablauf weiterhin verwenden möchte. + + + +In Git kann man diese Vorgehensweise gut abbilden, indem man für jedes Unterverzeichnis ein neues Git-Repository erzeugt. Zusätzlich kann man dann ein Superprojekt erzeugen und die ganzen Git-Repositorys als Submodul hinzufügen. Ein Vorteil dabei ist, dass man mit Hilfe von Tags und Branches im Superprojekt das Verhältnis der einzelnen Submodule zueinander festhalten kann. +### Häufige Probleme mit Submodulen ### +Die Arbeit mit Submodulen verläuft jedoch nicht immer reibungslos. Man muss verhältnismäßig gut aufpassen, wenn man in einem Submodul-Verzeichnis arbeitet. Wenn man nämlich den Befehl `git submodule update` ausführt, checkt Git den entsprechenden Zustand des Commits aus, aber checkt dabei keinen Branch aus. Diesen Zustand nennt man auch `detached HEAD`. Das bedeutet, dass die Datei HEAD direkt auf einen Commit zeigt und nicht, wie sonst üblich, auf eine symbolische Referenz, also zum Beispiel auf einen Branch. Das Problem dabei ist, dass man normalerweise in einem solchen Zustand nicht weiterarbeiten möchte, weil es sehr leicht vorkommen kann, dass Änderungen verloren gehen. Wenn man also den Befehl `git submodule update` aufruft, dann einen Commit in dem entsprechenden Submodul-Verzeichnis ausführt, ohne davor einen Branch auszuchecken, und dann noch einmal `git submodule update` im Superprojekt aufruft, ohne dass man die Änderungen im Submodul im Superprojekt eingecheckt hat, verliert man die ganzen Änderungen, ohne dass Git einen darauf vorher hinweist. Tatsächlich ist es so, dass die Änderungen nicht verloren gehen, aber es gibt keinen Branch, der auf die entsprechenden Commits hinzeigt, und damit kann es schwierig werden, die entsprechenden Commits wiederherzustellen beziehungsweise sichtbar zu machen. + +Um dieses Problem zu vermeiden, sollte man also immer in dem Submodul-Verzeichnis einen neuen Branch mit `git checkout -b work` oder auf eine andere Art und Weise erzeugen. Wenn man dann wieder das Aktualisieren des Submoduls ausführt, wird Git wieder den ursprünglichen Commit auschecken, allerdings hat man jetzt mit dem Branch einen Zeiger auf die neuen Commits und man kann sie leicht wieder auschecken. + +Wenn ein Projekt ein Submodul enthält und man im Superprojekt zwischen einzelnen Branches hin und her wechseln möchte, kann sich das manchmal auch schwierig gestalten. Wenn man zum Beispiel einen neuen Branch erzeugt, in diesem dann ein Submodul hinzufügt und dann wieder in den ursprünglichen Branch, welcher das Submodul noch nicht enthält, zurückwechselt, hat man im Arbeitsverzeichnis immer noch das Submodul-Verzeichnis, welches auch so dargestellt wird, als ob es von Git noch nicht verfolgt wird: + $ git checkout -b rack Switched to a new branch "rack" $ git submodule add git@github.com:schacon/rack.git rack @@ -1306,14 +1364,20 @@ Wenn Du die untere, genannte Zeile ausführst, führt Git automatisch nach jedem +In diesem Fall muss man das Verzeichnis entweder an einen anderen Ort verschieben oder löschen. Im letzteren Fall muss man aber wieder das Submodul komplett klonen, wenn man in den anderen Zweig zurückwechselt. Außerdem kann man dabei lokale Änderungen zunichte machen oder Zweige, welche man noch nicht gepusht hat, verlieren. + +Die letzte Falle, in die viele Leute tappen, tritt auf, wenn man bereits vorhandene Verzeichnisse in Submodule umwandeln will. Wenn man also Dateien, die bereits von Git verwaltet werden, entfernen und in ein entsprechendes Submodul verschieben möchte, muss man vorsichtig sein. Ansonsten können schwer zu behebende Probleme mit Git auftreten. Nehmen wir zum Beispiel an, dass Du die Dateien vom Rack-Projekt in ein Unterverzeichnis Deines Projekts abgelegt hast und diese jetzt aber in ein Submodul verschieben möchtest. Wenn Du das Unterverzeichnis einfach löschst und dann den Befehl `submodule add` ausführst, zeigt Dir Git folgende Fehlermeldung an: + $ rm -Rf rack/ $ git submodule add git@github.com:schacon/rack.git rack 'rack' already exists in the index +Man muss dann das Verzeichnis `rack` erst aus der Staging-Area entfernen. Danach kann man dann das Submodul erzeugen: + $ git rm -r rack $ git submodule add git@github.com:schacon/rack.git rack Initialized empty Git repository in /opt/testsub/rack/.git/ @@ -1325,11 +1389,15 @@ Wenn Du die untere, genannte Zeile ausführst, führt Git automatisch nach jedem +Wenn wir jetzt annehmen, dass Du diesen Vorgang innerhalb eines Zweigs durchgeführt hast und jetzt auf einen anderen Zweig, in dem das Submodul noch nicht existiert hat und damit die Dateien noch ganz normal im Repository enthalten waren, wechselst, erhält Du folgenden Fehler: + $ git checkout master error: Untracked working tree file 'rack/AUTHORS' would be overwritten by merge. +Dann musst Du das Submodul-Verzeichnis `rack` an einen anderen Ort verschieben, bevor Du diesen Branch auschecken kannst: + $ mv rack /tmp/ $ git checkout master Switched to branch "master" @@ -1338,17 +1406,27 @@ Wenn Du die untere, genannte Zeile ausführst, führt Git automatisch nach jedem +Wenn man dann wieder in den Zweig mit dem Submodul zurückwechseln will, erhält man ein leeres Verzeichnis `rack`. Um dieses zu befüllen, kannst Du entweder `git submodule update` ausführen oder Du kannst Deine Kopie von `/tmp/rack` wieder an den ursprünglichen Ort wiederherstellen. + ## Subtree Merging ## +Nachdem wir neben den Vor- und Nachteilen beim Arbeiten mit Submodulen kennengelernt haben, möchte ich jetzt noch eine alternative Lösung zeigen, wie man ähnliche Probleme lösen kann. Wenn Git etwas zusammenführt, also mergt, analysiert es die Teile, die es mergen muss. Auf Basis dieser Analyse entscheidet Git sich für eine geeignete Merging-Methode. Wenn man zwei Branches mergt, dann verwendet Git automatisch die sogenannte Recursive-Strategie. Wenn man mehr als zwei Branches mergt, verwendet Git die sogenannte Octopus-Strategie. Diese Strategien werden automatisch für Dich gewählt, weil die Recursive-Strategie normalerweise sehr gut geeignet ist, um einen Drei-Wege-Merge (engl. three-way merge) durchzuführen — zum Beispiel, wenn es mehr als einen gemeinsamen Vorgänger-Commit gibt — aber der Drei-Wege-Merge ist nur für das Mergen von zwei Branches geeignet. Die Octopus-Merge-Strategie kann mehrere Branches zusammenführen, aber es wird dabei vorsichtiger vorgegangen, um schwierig aufzulösende Konflikte zu vermeiden. Aus diesem Grund wird diese Strategie standardmäßig verwendet, wenn man mehr als zwei Branches zusammenführen möchte. + +Es gibt jedoch noch weitere Strategien, die man verwenden kann. Einer dieser Strategien ist der sogenannte Subtree-Merge. Dies kann verwendet werden, um unser Problem mit Unterprojekten zu lösen. Ich möchte Dir im Folgenden aufzeigen, wie man das Rack-Projekt aus dem letzten Kapitel einbindet und dabei den Subtree-Merge anstatt der Submodule verwendet. + +Das Prinzip, das hinter einem Subtree-Merge steckt, ist, dass man zwei Projekte hat und eines der Projekte wird in ein Unterverzeichnis des anderen Projekts abgebildet. Wenn man ein Subtree-Merge ausführt, ist Git schlau genug, um zu erkennen, dass ein Projekt ein Abbild von einem anderen Projekt ist und es kann den Merge in geeigneter Weise durchführen — das ist wirklich sehr erstaunlich. + +Als erstes musst Du dazu die Rack-Applikation zu Deinem Projekt hinzufügen. Dazu fügst Du das Rack-Projekt als neues Remote-Repository in Deinem Projekt hinzu und checkst dieses in einem separaten Branch aus: + $ git remote add rack_remote git@github.com:schacon/rack.git $ git fetch rack_remote warning: no common commits @@ -1368,6 +1446,8 @@ Wenn Du die untere, genannte Zeile ausführst, führt Git automatisch nach jedem +Nach der Ausführung der drei Befehle befindet sich das Rack-Projekt in Deinem Branch `rack_branch` und Dein eigenes Projekt liegt weiterhin im Branch `master`. Wenn man jetzt den jeweiligen Zweig auscheckt, sieht man die unterschiedlichen Inhalte im Wurzelverzeichnis: + $ ls AUTHORS KNOWN-ISSUES Rakefile contrib lib COPYING README bin example test @@ -1378,15 +1458,21 @@ Wenn Du die untere, genannte Zeile ausführst, führt Git automatisch nach jedem +Jetzt möchten wir das Rack-Projekt in Deinen Branch `master` als Unterverzeichnis hinzufügen. Dies kann man in Git mit dem Befehl `git read-tree` durchführen. In Kapitel 9 werde ich den Befehl `read-tree` und dessen verwandte Befehle näher erläutern. Hier möchte ich nur erklären, dass der Befehl das Wurzelverzeichnis eines Branches in die aktuelle Staging-Area und in das Arbeitsverzeichnis packt. Damit hast Du jetzt zu Deinem Branch `master` zurückgewechselt, den Inhalt des Branches `rack_branch` in das Unterverzeichnis `rack` im Branch `master` Deines Projekts hinterlegt: + $ git read-tree --prefix=rack/ -u rack_branch +Wenn Du jetzt einen Commit ausführst, erscheint es einem so, als ob die ganzen Dateien aus dem Rack-Projekt in diesem Unterverzeichnis liegen — als ob man das Projekt aus einem Tarball-Container hineinkopiert hätte. Das Besondere ist jetzt aber, dass man Änderungen zwischen den verschiedenen Branches jetzt einfach zusammenführen kann. Das bedeutet, wenn das Rack-Projekt aktualisiert wird, kann man sich diese Änderungen einfach holen, indem man in diesen Branch wechselt und dort einen Pull durchführt: + $ git checkout rack_branch $ git pull +Danach kann man diese Änderungen wieder in den Branch master mergen. Wenn man den Befehl `git merge -s subtree` verwendet, sollte dies einwandfrei funktionieren. Allerdings wird Git bei Ausführen dieses Befehls auch die jeweilige Historie mergen, was Du wahrscheinlich nicht haben möchtest. Um nun die Änderungen zu holen und eine entsprechende Commit-Nachricht vorzubereiten, hängt man einfach `--squash`, `--no-commit` und natürlich `-s subtree` als Option an: + $ git checkout master $ git merge --squash -s subtree --no-commit rack_branch Squash commit -- not updating HEAD @@ -1394,15 +1480,23 @@ Wenn Du die untere, genannte Zeile ausführst, führt Git automatisch nach jedem +Die ganzen Änderungen des Rack-Projekts wurden nun zusammengeführt, Du musst jetzt nur noch einen entsprechenden Commit durchführen. Man kann aber auch genau das Gegenteil machen: Man führt Änderungen im Unterverzeichnis `rack` des Branches master aus und mergt diese dann später in den Zweig `rack_branch`. Diesen kann man dann den Entwicklern des Rack-Projekts zur Verfügung stellen. + +Um die Unterschiede zwischen dem Inhalt in Deinem Verzeichnis `rack` und dem Code im Zweig `rack_branch` anzuzeigen, kann man keinen normalen Vergleich mit `diff` durchführen. Man muss stattdessen den Befehl `git diff-tree` verwenden und als Argument den zu vergleichenden Branch angeben: + $ git diff-tree -p rack_branch +Um Dein Verzeichnis `rack` mit dem letzten Stand des Branches `master` auf dem Server zu vergleichen, kannst Du folgenden Befehl verwenden: + $ git diff-tree -p rack_remote/master ## Zusammenfassung ## + +In diesem Kapitel hast Du viele ausgeklügelte Werkzeuge kennengelernt, die es Dir ermöglichen, Commits und die Staging-Area nach Deinen Vorstellungen zu beeinflussen. Wenn ein Problem in Deinem Projekt auftaucht, solltest Du jetzt leicht bestimmen können, welcher Commit den Fehler verursacht hat, sowie wann und von wem der Fehler begangen wurde. Wenn Du andere Projekte in Deinem Projekt verwenden möchtest, hast Du jetzt mehrere Möglichkeiten kennengelernt, wie Du dies handhaben kannst. An dieser Stelle solltest Du jetzt in der Lage sein, die meisten Dinge, die Du bei der täglichen Arbeit benötigst, in der Kommandozeile durchzuführen, ohne dass Dir dabei Schweißperlen auf der Stirn stehen. diff --git a/de/07-customizing-git/01-chapter7.markdown b/de/07-customizing-git/01-chapter7.markdown index 74dede055..1d9a629d2 100644 --- a/de/07-customizing-git/01-chapter7.markdown +++ b/de/07-customizing-git/01-chapter7.markdown @@ -115,7 +115,7 @@ Die Einstellung `core.pager` legt fest, welche Anwendung zur Seitenanzeige benut Wenn Du dies ausführst, wird Git immer die komplette Ausgabe aller Befehle anzeigen, egal wie lange sie ist. - + #### user.signingkey #### @@ -140,9 +140,9 @@ In Kapitel 2 habe ich bereits beschrieben, wie Du mit Hilfe der projektspezifisc #### help.autocorrect #### - + -Diese Option ist in Git ab Version 1.6.1 verfügbar. Wenn Du in Git 1.6 einen Befehl falsch schreibst, bekommst Du eine Meldung wie diese: +Diese Option ist in Git ab Version 1.6.1 verfügbar. Wenn Du in Git einen Befehl falsch schreibst, bekommst Du eine Meldung wie diese: $ git com git: 'com' is not a git-command. See 'git --help'. @@ -170,9 +170,9 @@ Wenn Du Git entsprechend konfigurierst, wird es den Großteil der Ausgaben autom $ git config --global color.ui true - + -Wenn dieser Wert gesetzt wurde, benutzt Git für seine Ausgaben Farben, sofern diese zu einem Terminal geleitet werden. Weitere mögliche Einstellungen sind ‚false‘, wodurch alle Farben deaktiviert werden, sowie ‚always‘, wodurch Farben immer aktiviert sind, selbst wenn Du Git Befehle in eine Datei oder über eine Pipe zu einem anderen Befehl umleitest. Diese Option wurde in Git 1.5.5 hinzugefügt. Solltest Du eine ältere Git Version benutzen, so musst Du alle Farbeinstellungen einzeln vornehmen. +Wenn dieser Wert gesetzt wurde, benutzt Git für seine Ausgaben Farben, sofern diese zu einem Terminal geleitet werden. Weitere mögliche Einstellungen sind ‚false‘, wodurch alle Farben deaktiviert werden, sowie ‚always‘, wodurch Farben immer aktiviert sind, selbst wenn Du Git Befehle in eine Datei oder über eine Pipe zu einem anderen Befehl umleitest. @@ -181,9 +181,9 @@ Du wirst selten die Einstellung `color.ui = always` benötigen. In den meisten F #### `color.*` #### - + -Falls Du im Detail einstellen willst, welche Befehle wie gefärbt werden, oder wenn Du eine ältere Version benutzt, dann stellt Git Verb-spezifische Farbeinstellungen zur Verfügung. Jede dieser Optionen kann auf `true`, `false`, oder `always` eingestellt werden: +Falls Du im Detail einstellen willst, welche Befehle wie gefärbt werden, dann stellt Git Verb-spezifische Farbeinstellungen zur Verfügung. Jede dieser Optionen kann auf `true`, `false`, oder `always` eingestellt werden: color.branch color.diff @@ -219,7 +219,7 @@ Da P4Merge für die üblichen Plattformen verfügbar ist, sollte es kein Problem Du kannst P4Merge hier herunterladen: - http://www.perforce.com/perforce/downloads/component.html + http://www.perforce.com/product/components/perforce-visual-merge-and-diff-tools @@ -468,25 +468,33 @@ Um Git anzuweisen alle `pbxproj` Dateien als Binärdateien zu behandeln, kannst *.pbxproj -crlf -diff - + -Ab jetzt wird Git nicht mehr versuchen CRLF Probleme zu lösen oder die Datei beim Commit oder Checkout zu ändern. Außerdem ermittelt Git keine Dateiunterschiede mehr und gibt diese auch nicht aus, wenn Du den Befehl ‚git show‘ oder ‚git diff‘ ausführst. Ab der Git Version 1.6 steht Dir auch ein Makro zur Verfügung, welches den Parametern `-crlf -diff` entspricht: +Ab jetzt wird Git nicht mehr versuchen CRLF Probleme zu lösen oder die Datei beim Commit oder Checkout zu ändern. Außerdem ermittelt Git keine Dateiunterschiede mehr und gibt diese auch nicht aus, wenn Du den Befehl `git show` oder `git diff` ausführst. Alternativ gibt es auch ein integriertes Makro `binary`, welches den Parametern `-crlf -diff` entspricht: *.pbxproj binary #### Diff bei Binärdateien #### - + -Mit Hilfe der Git Attribute können seit der Version 1.6, Unterschiede in binären Dateien effektiv und leicht angezeigt werden. Du kannst Git so konfigurieren, dass es automatisch Binärdateien in Textdateien umwandelt, damit sie mit einem normalen Diff verglichen werden können. +Mit Hilfe der Git Attribute können Unterschiede in binären Dateien effektiv und leicht angezeigt werden. Du kannst Git so konfigurieren, dass es automatisch Binärdateien in Textdateien umwandelt, damit sie mit einem normalen Diff verglichen werden können. Meist stellt sich aber die Frage, wie man binäre Daten in Text konvertieren soll. Wenn man ein Werkzeug findet, welches einem diese Konvertierung abnimmt und die binäre Daten in ein Textformat umwandelt, ist dies meist die beste Lösung. Leider gibt es nur sehr wenige binäre Formate, die sich dafür eignen, dass man sie in lesbare Textformate umwandelt (Ich denke dabei zum Beispiel an Audio-Daten). Wenn dies der Fall ist und Du keine geeignete Möglichkeit gefunden hast, die Daten in lesbare Form zu wandeln, dann ist es oft relativ einfach eine entsprechende Beschreibung des eigentlichen Inhalts zu erhalten. Alternativ gibt es noch Metadaten, wobei Metadaten einem nicht ein vollständiges Abbild vom Dateiinhalt liefern können, aber in diesem Fall ist das besser als gar nichts. + + + +Im folgenden Abschnitt werden wir beide Möglichkeiten besprechen, wie man für weit verbreitete binäre Formate eine lesbare Form für einen Vergleich erhält. + + + +Anmerkung: Es gibt verschiedene Arten von binären Formaten, welche Text beinhalten, und es ist meist sehr schwierig einen passenden Konverter zu finden. In solchen Fällen kann man sein Glück mit dem `strings`-Programm versuchen. Manche der Formate verwenden ein UTF-16 Encoding oder andere Zeichentabellen. In diesem Fall wird es mit dem Programm `strings` meist nicht funktionieren. Da `strings` jedoch auf den meisten Mac- und Linux-Systemen verfügbar ist, sollte man es durchaus auf einen Versuch ankommen lassen. ##### MS Word files ##### - + -Da das eine ziemlich praktische, aber nicht sehr bekannt Funktionalität ist, werde ich einige Beispiele besprechen. Als erstes werden wir diese Technik benutzen um eines der lästigsten Probleme der Menschheit zu lösen: Versionskontrolle von Word Dokumenten. Jeder weiß, dass Word der schrecklichste Editor der Welt ist, aber trotzdem benutzt ihn jeder. Wenn Du Word Dokumente versionieren willst, kannst Du sie in Dein Repository packen und ab und zu einen Commit durchführen. Aber wozu ist das nützlich? Wenn Du einen Vergleich mit `git diff` ausführst, erhälst Du ähnliche Ausgabe wie diese: +Als erstes werden wir die beschriebene Technik benutzen um eines der lästigsten Probleme der Menschheit zu lösen: Versionskontrolle von Word Dokumenten. Jeder weiß, dass Word der schrecklichste Editor der Welt ist, aber trotzdem benutzt ihn jeder. Wenn Du Word Dokumente versionieren willst, kannst Du sie in Dein Repository packen und ab und zu einen Commit durchführen. Aber wozu ist das nützlich? Wenn Du einen Vergleich mit `git diff` ausführst, erhälst Du ähnliche Ausgabe wie diese: $ git diff diff --git a/chapter1.doc b/chapter1.doc @@ -499,26 +507,22 @@ Du kannst zwei Versionen nicht direkt vergleichen, außer Du checkst sie aus und *.doc diff=word - + -Dies weist Git an, dass auf jede Datei, die diesem Dateimuster (.doc) entspricht, der „word“ Filter angewandt werden soll, wenn Du versuchst, einen Diff mit Dateiunterschieden anzusehen. Was ist nun der „word“ Filter? Dieser muss von Dir noch konfiguriert werden. Du kannst Git so konfigurieren, dass es das `strings` Programm verwendet um Word Dokumente in lesbare Textdateien zu konvertieren. Bei jedem Diff wird Git diese Konvertierung durchführen: +Dies weist Git an, dass auf jede Datei, die diesem Dateimuster (.doc) entspricht, der „word“ Filter angewandt werden soll, wenn Du versuchst, einen Diff mit Dateiunterschieden anzusehen. Was ist nun der „word“ Filter? Dieser muss von Dir noch konfiguriert werden. Du kannst Git so konfigurieren, dass es das `catdoc` Programm verwendet um Word Dokumente in lesbare Textdateien zu konvertieren. `catdoc` wurde speziell dafür entwickelt um lesbaren Text aus binären MS Word Dokumenten zu extrahieren (du erhälst es unter `http://www.wagner.pp.ru/~vitus/software/catdoc/`). Bei jedem Diff wird Git diese Konvertierung durchführen: - $ git config diff.word.textconv strings + $ git config diff.word.textconv catdoc Dieser Befehl fügt in der Datei `.git/config` eine Sektion mit folgendem Aufbau hinzu: [diff "word"] - textconv = strings - - - -Anmerkung: Es gibt verschiedene Arten von `.doc` Dateien. Manche verwenden UTF-16 Kodierung oder andere Zeichensätze. Das führt dazu, dass `strings` nichts verwertbares findet. Probier Dein Glück. + textconv = catdoc - + -Bei jedem Vergleich von zwei Schnappschüssen wird Git Dateien mit der Dateiendung `.doc` durch den „word“ Filter jagen, welcher durch das `strings` Programm definiert ist. Das erzeugt gut lesbare Textversionen Deiner Word Dateien, die für den Vergleich herangezogen werden. +Bei jedem Vergleich von zwei Schnappschüssen wird Git Dateien mit der Dateiendung `.doc` durch den „word“ Filter jagen, welcher durch das `catdoc` Programm definiert ist. Das erzeugt gut lesbare Textversionen Deiner Word Dateien, die für den Vergleich herangezogen werden. @@ -529,17 +533,16 @@ Dazu ein Beispiel. Ich habe Kapitel 1 des Buches in ein Word-Dokument einfgefüg index c1c8a0a..b93c9e4 100644 --- a/chapter1.doc +++ b/chapter1.doc - @@ -8,7 +8,8 @@ re going to cover Version Control Systems (VCS) and Git basics - re going to cover how to get it and set it up for the first time if you don - t already have it on your system. - In Chapter Two we will go over basic Git usage - how to use Git for the 80% - -s going on, modify stuff and contribute changes. If the book spontaneously - +s going on, modify stuff and contribute changes. If the book spontaneously - +Let's see if this works. + @@ -128,7 +128,7 @@ and data size) + Since its birth in 2005, Git has evolved and matured to be easy to use + and yet retain these initial qualities. It’s incredibly fast, it’s + very efficient with large projects, and it has an incredible branching + -system for non-linear development. + +system for non-linear development (See Chapter 3). - + -Git war erfolgreich und zeigt nun kurz und bündig an, dass ich den Text „Let's see if this works“ hinzugefügt habe, was korrekt ist. Es ist nicht perfekt, es wird etwas zufälliger Kram am Ende angefügt — aber es funktioniert. Falls Du einen guten Word-nach-Text Konverter findest oder schreibst, dann ist diese Lösung wahrscheinlich äußerst effektiv. Für den Anfang sollte `strings` für die meisten Binärformate jedoch ausreichen, vor allem da es für die meisten Mac und Linux Systeme verfügbar ist. +Git war erfolgreich und zeigt nun kurz und bündig an, dass ich den Text „(See Chapter 3)“ hinzugefügt habe, was korrekt ist. Wie du siehst, funktioniert perfekt. ##### OpenDocument Textdateien ##### @@ -815,9 +818,9 @@ Genau wie bei vielen anderen Versionskontrollsystemen gibt es auch bei Git die M ### Installieren eines Hooks ### - + -Sämtliche Hooks werden im `hooks` Unterverzeichnis des Git Verzeichnisses gespeichert. In den meisten Projekten wird das `.git/hooks` sein. Git installiert in dieses Verzeichnis standardmäßig Beispielskripte. Einige davon sind auch ohne Änderung nützlich und sofort einsetzbar. Zusätzlich dokumentieren diese Beispiele die Eingabewerte des jeweiligen Skripts. Alle Beispiele sind Shellskripte, die hier und da ein Paar Zeilen Perl Code enthalten. Prinzipiell sollte aber jedes ausführbare Skript funktionieren, wenn es korrekt benannt wird. Du kannst also die Skriptsprache Deiner Wahl verwenden, z.B. Ruby oder Python. Ab Version 1.6 haben die Beispieldateien die Endung .sample, sie müssen also noch umbenannt werden. In älteren Versionen sind die Beispieldateien korrekt benannt, aber dafür nicht ausführbar. +Sämtliche Hooks werden im `hooks` Unterverzeichnis des Git Verzeichnisses gespeichert. In den meisten Projekten wird das `.git/hooks` sein. Git installiert in dieses Verzeichnis standardmäßig Beispielskripte. Einige davon sind auch ohne Änderung nützlich und sofort einsetzbar. Zusätzlich dokumentieren diese Beispiele die Eingabewerte des jeweiligen Skripts. Alle Beispiele sind Shellskripte, die hier und da ein Paar Zeilen Perl Code enthalten. Prinzipiell sollte aber jedes ausführbare Skript funktionieren, wenn es korrekt benannt wird. Du kannst also die Skriptsprache Deiner Wahl verwenden, z.B. Ruby oder Python. Die Beispieldateien haben die Endung .sample, sie müssen also nur noch umbenannt werden. @@ -1114,9 +1117,9 @@ Ab jetzt haben alle Benutzer nur für die jeweils freigegebenen Verzeichnisse Zu #### Verweigern von Pushes, welche nicht einem Fast-Forward entsprechen #### - + -Nun müssen wir unser System nur noch so einrichten, dass es nur Fast-Forward Push-Operationen zulässt. Ab der Version 1.6 von Git kann man dazu die `receive.denyDeletes` und `receive.denyNonFastForwards` Konfigurationsparameter verwenden. In älteren Versionen benötigt man dafür einen Hook und man kann diesen dann so konfigurieren, dass die Regeln nur für bestimmte Benutzer gelten. +Nun müssen wir unser System nur noch so einrichten, dass es nur Fast-Forward Push-Operationen zulässt. Man verwendet dafür die `receive.denyDeletes` und `receive.denyNonFastForwards` Konfigurationsparameter. Das gleiche Ergebnis kann man aber auch über einen Hook erreichen und diesen kann man dann so konfigurieren, dass die Regeln nur für bestimmte Benutzer gelten. diff --git a/de/08-git-and-other-scms/01-chapter8.markdown b/de/08-git-and-other-scms/01-chapter8.markdown index 757762e12..19d5fc35b 100644 --- a/de/08-git-and-other-scms/01-chapter8.markdown +++ b/de/08-git-and-other-scms/01-chapter8.markdown @@ -464,8 +464,8 @@ Auf diese Weise müllst Du Dein Projekt nicht mit `.gitignore`-Dateien zu. Das i Die `git svn`-Werkzeuge sind sehr nützlich, wenn Du derzeit (noch) an einen Subversion-Server gebunden bist oder Dich anderweitig in einer Entwicklungsumgebung befindest, die nicht auf einen Subversion-Server verzichten kann. Wie auch immer: Du solltest es als eine Art gestutztes Git ansehen. Anderenfalls läufst Du Gefahr, Dich und Deine Kollegen durcheinander zu bringen. Um dieses Kliff zu umschiffen, solltest Du folgende Richtlinien befolgen: - + + * Versuch, eine „geradlinige“ Git-Historie zu führen, die keine von `git merge` durchgeführten Merges enthält. Alle Arbeiten, die Du außerhalb des Hauptzweiges durchführst, solltest Du mit `rebase` in ihn aufnehmen anstatt sie zu mit `merge` zusammenzuführen. * Setz keinen zusätzlichen, externen Git-Server auf, mit dem Du arbeiten möchtest. Du kannst einen aufsetzen um die Klone für neue Entwickler zu beschleunigen, aber Du solltest keine Änderungen dorthin pushen, die keine `git-svn-id`-Einträge haben. Du solltest vielleicht sogar darüber nachdenken, einen `pre-receive`-Hook einzusetzen, der jede Commit-Nachricht auf eine `git-svn-id` prüft und bestimmte Pushes ablehnt, bei denen diese IDs fehlt. @@ -517,7 +517,7 @@ Dies erzeugt Dir die Log-Ausgabe im XML-Format — Du suchst damit nach den Auto Du kannst diese Datei dann `git svn` zur Verfügung stellen um das Tool dabei zu unterstützen, die Autoreninformationen besser zu mappen. Du kannst `git svn` ebenfalls mitteilen, dass es die Metadaten nicht einbeziehen soll, die Subversion normalerweise importiert, indem Du dem `clone` oder `init` Kommando die `--no-metadata`-Option mitgibst. - $ git-svn clone http://my-project.googlecode.com/svn/ \ + $ git svn clone http://my-project.googlecode.com/svn/ \ --authors-file=users.txt --no-metadata -s my_project @@ -818,7 +818,7 @@ Das letzte, das wir jetzt noch machen müssen, ist, die gegenwärtige Marke zur return mark - + $stdout.binmode diff --git a/de/09-git-internals/01-chapter9.markdown b/de/09-git-internals/01-chapter9.markdown index e58370210..947c36bc9 100644 --- a/de/09-git-internals/01-chapter9.markdown +++ b/de/09-git-internals/01-chapter9.markdown @@ -1,36 +1,36 @@ -# Git Internas # +# Git Interna # -Möglicherweise hast Du dieses Kapitel hier direkt aufgeschlagen, vorherige Kapitel ausgelassen, oder bist hierher gelangt, nachdem Du alle vorherigen Kapitel gelesen hast. Wie auch immer, in diesem Kapitel wirst Du mit mit den internen (xxx) und der Implementation von Git befassen. Meine eigene Erfahrung damit, diese Dinge zu lernen, war dass sie unerlässlich ist, um zu verstehen, wie unheimlich mächtig und flexibel Git ist. Allerdings gibt es Leute, die der Ansicht sind, dass sie auch verwirrend und unnötig komplex für Anfänger sein könne. Deshalb habe ich mich entschieden, dieses Kapitel an das Ende des Buches zu verlegen. Du kannst es, ganz wie es Dir beliebt, früher oder später einschieben. +Möglicherweise hast Du dieses Kapitel hier direkt aufgeschlagen, vorherige Kapitel ausgelassen, oder bist hierher gelangt, nachdem Du alle vorherigen Kapitel gelesen hast. Wie auch immer, in diesem Kapitel werden wir uns mit der internen Funktionsweise und der Implementierung von Git befassen. Meine eigene Erfahrung ist, dass das Lernen dieser Dinge unerlässlich ist, um zu verstehen, wie unheimlich mächtig und flexibel Git ist. Allerdings gibt es Leute, die der Ansicht sind, dass sie auch verwirrend und unnötig komplex für Anfänger sein können. Deshalb habe ich mich entschieden, dieses Kapitel an das Ende des Buches zu verlegen. Du kannst es, ganz wie es Dir beliebt, früher oder später einschieben. -Lass uns also loslegen. Zunächst will ich betonen, falls das bisher noch nicht klargeworden ist, dass Git im seinen Grundzügen ein Dateisystem ist, dessen Inhalte addressierbar sind (xxx content-addressable filesystem ??? xxx) und auf dem ein VCS Interface sitzt. Wir werden gleich genauer darauf eingehen, was das heißt. +Lass uns also loslegen. Zunächst will ich betonen, falls das bisher noch nicht klargeworden ist, dass Git im seinen Grundzügen ein Dateisystem ist, dessen Inhalte addressierbar sind und auf dem eine VCS-Schnittstelle aufgesetzt ist. Wir werden gleich genauer darauf eingehen, was das heißt. -In den frühen Tagen von Git (d.h. vor der Version 1.5.) war das Interface sehr viel komplexer, weil es diese Dateisystem Eigenschaften stark betonte – im Gegensatz zu einem ausgearbeiteten VCS. In den letzten Jahren wurde das Interface dann stückweise verbessert und verfeinert, sodass es heute so einfach verständlich und einfach zu verwenden ist, wie alle möglichen vergleichbaren Systeme, die es gibt. Allerdings besteht scheinbar weiterhin das Vorurteil, dass das Git Interface komplex und schwer zu erlernen sei. +In den frühen Tagen von Git (d.h. vor Version 1.5) war die Benutzerschnittstelle sehr viel komplexer, weil es die Dateisystem-Eigenschaften stark betonte – im Gegensatz zu einem herkömmlichen VCS. In den letzten Jahren wurde die Benutzerschnittstelle dann stückweise verbessert und verfeinert, sodass es heute so einfach verständlich und einfach zu verwenden ist, wie andere vergleichbare Systeme, die auf dem Markt erhältlich sind. Allerdings besteht scheinbar weiterhin das Vorurteil, das Git-Interface sei komplex und schwer zu erlernen. -Die Dateisystem Ebene ist erstaunlich cool, weshalb ich in diesem Kapitel zuerst darauf eingehen werde. Als nächstes lernst Du etwas über die Transport Mechanismen und Repository Wartungsaufgaben, mit denen Du möglicherweise irgendwann zu tun bekommen wirst. +Die inhaltsbasiert adressierbare Dateisystem-Ebene ist erstaunlich cool, weshalb ich in diesem Kapitel zuerst darauf eingehen werde. Als Nächstes lernst Du etwas über die Transport-Mechanismen und Repository-Wartungsaufgaben, mit denen Du möglicherweise irgendwann zu tun bekommen wirst. ## Plumbing und Porcelain ## -In diesem Buch haben wir Git besprochen, indem wir vielleicht 30 Befehle wie `checkout`, `branch`, `remote` und so weiter verwendet haben. Weil Git aber ursprünglich als ein Werkzeugkasten konzipiert war, un nicht so sehr als ein komplettes, anwenderfreundliches VCS, gibt es auch eine Reihe von Befehlen, die ihre Arbeit auf einer sehr viel grundlegenderen Ebene verrichten. Viele davon sind ursprünglich entwickelt worden, um als UNIX Befehle miteinander verkettet zu werden oder aus Scripten heraus aufgerufen zu werden. Diese Befehle werden oft als „plumbing“ (xxx) Befehle zusammengefasst, während die eher anwenderfreundlichen Befehle „porcelain“ (d.h. Porzellan) genannt werden. +In diesem Buch haben wir Git besprochen, indem wir vielleicht 30 Befehle wie `checkout`, `branch`, `remote` und so weiter verwendet haben. Weil Git aber ursprünglich als ein Werkzeugkasten konzipiert war und nicht so sehr als ein komplettes, anwenderfreundliches VCS, gibt es auch eine Reihe von Befehlen, die ihre Arbeit auf einer sehr viel grundlegenderen Ebene verrichten. Viele davon sind ursprünglich entwickelt worden, um als UNIX-Befehle miteinander verkettet zu werden oder aus Skripten heraus aufgerufen zu werden. Diese Befehle werden oft als „plumbing“-Befehle (Klempner-Befehle) zusammengefasst, während die eher anwenderfreundlichen Befehle „porcelain“ (d.h. Porzellan) genannt werden. -Die ersten acht Kapitel dieses Buches haben sich fast ausschließlich mit „porcelain“ Befehlen befasst. In diesem Kapitel gehen wir dagegen auf die zugrundeliegenden „plumbing“ Befehle ein, u.a. weil sie Dir den Zugriff auf Gits innere Abläufe ermöglichen, und weil sie dabei helfen, zu verstehen, warum Git tut, was es tut. Diese Befehle sind nicht unbedingt dazu bestimmt direkt (xxx on the command line xxx) ausgeführt zu werden, sondern sind als Bausteine für Werkzeuge und Scripts gemeint. +Die ersten acht Kapitel dieses Buches haben sich fast ausschließlich mit „Porcelain“-Befehlen befasst. In diesem Kapitel gehen wir dagegen auf die zugrundeliegenden „Plumbing“-Befehle ein, u.a. weil sie Dir den Zugriff auf die inneren Abläufe von Git ermöglichen, und weil sie dabei helfen, zu verstehen, warum Git tut, was es tut. Diese Befehle sind nicht dazu gedacht, manuell in der Eingabeaufforderung ausgeführt zu werden, sondern sind als Bausteine für Werkzeuge und Skripts gemeint. -Wenn Du `git init` in einem neuen oder bereits bestehenden Verzeichnis ausführst, erzeugt Git das `.git` Verzeichnis, das fast alle Dateien enthält, die Git intern speichert und ändert. Wenn Du eine Sicherheitskopie Deines Repositories anlegen oder es duplizieren willst, dann reicht aus, dieses Verzeichnis zu kopieren. Dieses ganze Kapitel handelt praktisch nur von den Inhalten dieses Verzeichnisses – die so aussehen: +Wenn Du `git init` in einem neuen oder bereits bestehenden Verzeichnis ausführst, erzeugt Git das `.git`-Verzeichnis, das fast alle Dateien enthält, die Git intern speichert und ändert. Wenn Du eine Sicherheitskopie Deines Repositorys anlegen oder es duplizieren willst, dann reicht es aus, dieses Verzeichnis zu kopieren. Dieses ganze Kapitel handelt praktisch nur von den Inhalten dieses Verzeichnisses. Schauen wir es uns einmal an: $ ls HEAD @@ -45,19 +45,19 @@ Wenn Du `git init` in einem neuen oder bereits bestehenden Verzeichnis ausführs -Möglicherweise findest Du darin weitere Dateien. Obiges stammt aus einem mit `git init` neuangelegten Repository – das sind also die Standardinhalte. Der Ordner `branches` wird von neueren Git Versionen nicht mehr verwendet, und die Datei `descriptions` wird nur vom Programm GitWeb benötigt. Du kannst sie also ignorieren. Die Datei `config` enthält Deine Projekt-spezifischen Konfigurationsoptionen, und im Ordner `info` befindet sich eine Datei, die globale Dateiausschlusspatterns (xxx) enthält, die Du nicht in jeder .gitignore Datei neu spezifizieren willst. Das `hooks` Verzeichnis enthält die client- oder serverseitigen Hook Scripte, die wir in Kapitel 7 besprochen haben. +Möglicherweise findest Du darin weitere Dateien. Obiges stammt aus einem mit `git init` neu angelegten Repository – das sind also die Standardinhalte. Der Ordner `branches` wird von neueren Git-Versionen nicht mehr verwendet, und die Datei `descriptions` wird nur vom Programm GitWeb benötigt. Du kannst sie also ignorieren. Die Datei `config` enthält Deine projekt-spezifischen Konfigurationsoptionen, und im Ordner `info` befindet sich eine Datei, die globale Dateiausschlussmuster enthält, die Du nicht in jeder .gitignore-Datei neu spezifizieren willst. Das `hooks`-Verzeichnis enthält die client- oder serverseitigen Hook-Skripte, die wir in Kapitel 7 besprochen haben. -Damit bleiben vier wichtige Einträge übrig: die Dateien `HEAD` und `index` und die Verzeichnisse `objects` und `refs`. Dies sind die Kernkomponenten eines Git Repositories: Im `objects` Verzeichnis befinden sich die Inhalte der Datenbank. Das `refs` Verzeichnis enthält Referenzen auf Commit Objekte (Branches) in dieser Datenbank. Die Datei `HEAD` zeigt auf denjeningen Branch, den Du gegenwärtig ausgecheckt hast, und in der Datei `index` verwaltet Git die Informationen der Staging Area. Wir werden auf diese Elemente jetzt im einzelnen darauf eingehen, sodass Du nachvollziehen kannst, wie Git intern arbeitet. +Damit bleiben vier wichtige Einträge übrig: die Dateien `HEAD` und `index` und die Verzeichnisse `objects` und `refs`. Dies sind die Kernkomponenten eines Git-Repositorys. Im `objects`-Verzeichnis befinden sich die Inhalte der Datenbank. Das `refs`-Verzeichnis enthält Referenzen auf Commit-Objekte (Branches) in dieser Datenbank. Die Datei `HEAD` zeigt auf denjeningen Branch, den Du gegenwärtig ausgecheckt hast, und in der Datei `index` verwaltet Git die Informationen der Staging-Area. Wir werden auf diese Elemente jetzt im einzelnen darauf eingehen, sodass Du nachvollziehen kannst, wie Git intern arbeitet. ## Git Objekte ## - + + -Git ist ein Dateisystem, das Inhalte addressieren kann. Prima. Aber was heißt das? Es bedeutet, dass Git im Kern nichts anderes ist als ein einfacher Key-Value-Store („Schlüssel-Wert-Speicher“). Du kannst darin jede Art von Inhalt ablegen und Git wird einen Schlüssel dafür zurückgeben, den Du dann verwenden kannst, um diesen Inhalt jederzeit nachzuschlagen. Um das auszuprobieren, kannst Du den Plumbing Befehl `hash-object` verwenden. Dieser nimmt einen Inhalt an, speichert ihn in Deinem `.git` Verzeichnis und gibt Dir den Schlüssel zurück, unter dem der Inhalt gespeichert wurde. Dazu initialisierst Du als erstes ein neues Git Repository und verifizierst, dass das `objects` Verzeichnis leer ist: +Git ist ein Dateisystem, das Inhalte addressieren kann. Prima. Aber was heißt das? Es bedeutet, dass Git im Kern nichts anderes ist als ein einfacher Key-Value-Store („Schlüssel-Wert-Speicher“). Du kannst darin jede Art von Inhalt ablegen und Git wird einen Schlüssel dafür zurückgeben, den Du dann verwenden kannst, um diesen Inhalt jederzeit nachzuschlagen. Um das auszuprobieren, kannst Du den Plumbing-Befehl `hash-object` verwenden. Dieser nimmt Daten entgegen, speichert diese in Deinem `.git`-Verzeichnis und gibt Dir den Schlüssel zurück, unter dem der Inhalt gespeichert wurde. Dazu initialisierst Du als erstes ein neues Git-Repository und verifizierst, dass das `objects`-Verzeichnis leer ist: $ mkdir test $ cd test @@ -72,32 +72,32 @@ Git ist ein Dateisystem, das Inhalte addressieren kann. Prima. Aber was heißt d -Git hat also ein Verzeichnis `objects` und darin die `pack` und `info` Unterverzeichnisse angelegt, bisher aber keine weiteren Dateien. Als nächsten speichern wir einen Text in dieser Git Datenbank: +Git hat also ein Verzeichnis `objects` und darin die Unterverzeichnisse `pack` und `info` angelegt, bisher aber keine weiteren Dateien. Als nächsten speichern wir einen Text in dieser Git-Datenbank: $ echo 'test content' | git hash-object -w --stdin d670460b4b4aece5915caf5c68d12f560a9fe3e4 -Die Option `-w` weist `git hash-object` an, das Objekt zu speichern. Andernfalls würde Dir der Befehl lediglich den Schlüssel mitteilen. `--stdin` weist den Befehl an, den Inhalt von aus der Standardeingabe zu lesen. Wenn Du diese Option weglässt, erwartet der Befehl zusätzlich einen Dateipfad. Die Ausgabe ist eine 40 Zeichen langer SHA-1 Hash, der eine Prüfsumme des gespeicherten Inhaltes darstellt (wir gehen auf diese Hashes gleich noch genauer ein). Git hat jetzt außerdem eine neue Datei in der Datenbank angelegt: +Die Option `-w` weist `git hash-object` an, das Objekt zu speichern. Andernfalls würde Dir der Befehl lediglich den Schlüssel mitteilen. `--stdin` weist den Befehl an, den Inhalt von der Standardeingabe einzulesen. Wenn Du diese Option weglässt, erwartet der Befehl zusätzlich einen Dateipfad. Die Ausgabe ist ein 40 Zeichen langer SHA-1-Hash, der eine Prüfsumme des gespeicherten Inhaltes darstellt (wir gehen auf diese Hashes gleich noch genauer ein). Git hat jetzt außerdem eine neue Datei in der Datenbank angelegt: $ find .git/objects -type f .git/objects/d6/70460b4b4aece5915caf5c68d12f560a9fe3e4 -D.h., im `objects` Verzeichnis befindet sich genau eine Datei. Auf diese Weise Git speichert Inhalte (xxx wieso initially? xxx): in jeweils einer Datei pro Inhalt, referenziert durch den SHA-1 Hash des Inhaltes und seines Headers (xxx Kopfdaten? xxx). Der Name des Unterverzeichnis `d6` sind die ersten zwei Zeichen des SHA-1 Hashes und der Dateiname die verbleibenden 38 Zeichen. +Jetzt liegt im Verzeichnis `objects` genau eine Datei. Anfangs speichert Git den Inhalt auf diese Art und Weise: In jeweils einer einzelnen Datei werden die Daten gespeichert, referenziert durch den SHA-1-Hash des Inhaltes und seines Headers. Der Name des Unterverzeichnis `d6` entspricht den ersten zwei Zeichen des SHA-1-Hashes. Die verbleibenden 38 Zeichen werden als Dateiname verwendet. -Mit dem Befehl `git cat-file` kannst Du den jeweiligen Inhalt nachschlagen. Dieser Befehl ist so etwas wie ein Schweizer Taschenmesser, wenn es um Objekte in der Git Datenbank geht. Wenn Du die Option `-p` übergibst, versucht `git cat-file`, die Art des Inhaltes (z.B. den Dateitypen xxx) herauszufinden und die Anzeige entsprechend lesbar zu formatieren: +Mit dem Befehl `git cat-file` kannst Du den jeweiligen Inhalt nachschlagen. Dieser Befehl ist so etwas wie ein Schweizer Taschenmesser, wenn es um Objekte in der Git-Datenbank geht. Wenn Du die Option `-p` übergibst, versucht `git cat-file`, die Art des Inhaltes herauszufinden und lesbar darzustellen: $ git cat-file -p d670460b4b4aece5915caf5c68d12f560a9fe3e4 test content -Auf diese Weise kannst Du also Inhalte zur Datenbank hinzufügen und von dort wieder nachschlagen. Wenn Du beispielsweise eine einzelne Datei versionskontrollieren willst, kannst Du zunächst die Datei anlegen und den Inhalt in der Datenbank speichern: +Auf diese Weise kannst Du also Inhalte zu Git hinzufügen und von dort wieder auslesen. Das klappt auch mit Dateiinhalten. Wenn Du beispielsweise eine einzelne Datei versionieren willst, legst Du dazu die Datei zunächst an und speicherst ihren Inhalt in der Datenbank: $ echo 'version 1' > test.txt $ git hash-object -w test.txt @@ -113,7 +113,7 @@ Dann kannst Du Änderungen vornehmen und die Datei erneut speichern: -Die Datenbank enthält jetzt zwei weitere Versionen der Datei neben dem ursprünglich gespeicherten Inhalt (xxx): +Die Datenbank enthält jetzt zwei weitere Versionen der Datei neben dem ursprünglich gespeicherten Inhalt: $ find .git/objects -type f .git/objects/1f/7a7a472abf3dd9643fd615f6da379c4acb3e3a @@ -138,17 +138,17 @@ Oder die zweite Version: -Sich den SHA-1 Hash für jede Version merken zu müssen, ist allerdings nicht sonderlich praktisch. Außerdem speicherst Du nicht den Dateinamen in der Datenbank, sondern lediglich den Inhalt der Datei. Ein solcher Objekttyp wird als „Blob“ bezeichnet. Mit `git cat-file -t` kannst Du Git nach dem Typ eines Objektes in der Datenbank fragen: +Sich den SHA-1-Hash für jede Version merken zu müssen, ist allerdings nicht sonderlich praktisch. Außerdem speicherst Du nicht den Dateinamen in der Datenbank, sondern lediglich den Inhalt der Datei. Ein solcher Objekttyp wird als „Blob“ bezeichnet. Mit `git cat-file -t` kannst Du Git nach dem Typ eines Objektes in der Datenbank fragen: $ git cat-file -t 1f7a7a472abf3dd9643fd615f6da379c4acb3e3a blob -### Baum Objekte ### +### Baum-Objekte ### -Als nächstes schauen wir uns den Objekttyp „Tree“ (Baum) an, der es ermöglicht, Dateinamen zu speichern und Dateien zu gruppieren. Git speichert Inhalte in einer ähnlichen Weise wie das UNIX Dateisystem, allerdings ein bisschen vereinfacht. Sie werden als Tree und Blob Objekte abgelegt, wobei die Trees mit UNIX Verzeichnis Einträgen korrespondieren und Blobs mehr oder weniger mit den inode Einträgen bzw. Datei Inhalten. Ein einzelnes Baum Objekt enthält einen oder mehrere Einträge, von denen jeder ein SHA-1 Hash ist, der wiederum einen Blob oder einen Untertree referenziert. Jeder dieser Einträge verfügt außerdem über einen Modus, Typ und Dateinamen. Beispielsweise sieht das aktuelle Tree Objekt im simplegit Projekt möglicherweise so aus: +Als Nächstes schauen wir uns den Objekttyp „Tree“ (Baum) an, der es ermöglicht, Dateinamen zu speichern und Dateien zu gruppieren. Git speichert Inhalte in einer ähnlichen Weise wie das UNIX-Dateisystem, allerdings ein bisschen vereinfacht. Sie werden als Tree- und Blob-Objekte abgelegt, wobei die Trees mit UNIX-Verzeichnis-Einträgen korrespondieren und Blobs mehr oder weniger mit den Inode-Einträgen bzw. Datei-Inhalten. Ein einzelnes Baum-Objekt enthält einen oder mehrere Einträge, von denen jeder ein SHA-1-Hash ist, der wiederum einen Blob oder einen Untertree referenziert. Jeder dieser Einträge verfügt außerdem über einen Modus, Typ und Dateinamen. Beispielsweise sieht das aktuelle Tree-Objekt im simplegit-Projekt möglicherweise so aus: $ git cat-file -p master^{tree} 100644 blob a906cb2a4a904a152e80877d4088654daad0c859 README @@ -157,7 +157,7 @@ Als nächstes schauen wir uns den Objekttyp „Tree“ (Baum) an, der es ermögl -Die `master^{tree}` Syntax spezifiziert, dass wir an dem Tree Objekt interessiert sind, auf das der letzte Commit des `master` Branches zeigt. Beachte, dass das `lib` Unterverzeichnis nicht auf ein Blob, sondern wiederum auf einen weiteren Baum zeigt. +Die `master^{tree}`-Syntax spezifiziert, dass wir an dem Tree-Objekt interessiert sind, auf das der letzte Commit des Branches `master` zeigt. Beachte, dass das Unterverzeichnis `lib` nicht auf ein Blob, sondern wiederum auf einen weiteren Baum zeigt. $ git cat-file -p 99f1a6d12cb4b6f19c8655fca46c3ecf317074e0 100644 blob 47c6340d6459e05787f644c2447d2595f5d3a54b simplegit.rb @@ -169,22 +169,22 @@ Git speichert Daten also, konzeptuell gesehen, in etwa wie in Bild 9-1 dargestel Insert 18333fig0901.png -Bild 9-1. Vereinfachte Darstellung des Git Datenmodels. +Bild 9-1. Vereinfachte Darstellung des Git-Datenmodels. -Du kannst auch Deine eigenen Tree Objekte anlegen. Git erzeugt Trees normalerweise, indem es die Inhalte der Staging Area nimmt und als ein Tree Objekt speichert. D.h., um ein Tree Objekt anzulegen, musst Du zunächst einen Index (d.h. eine Staging Area) erzeugen, indem Du einige Dateien hinzufügst. Um einen einzelnen Eintrag in den Index zu schreiben – z.B. die erste version der test.txt Datei – kannst Du den Plumbing Befehl `git update-index` verwenden, der eine frühere Version dieser Datei künstlich zu einer neuen Staging Area hinzufügt. Du musst ihm die `--add` Option übergeben, weil die Datei bisher noch nicht in der Staging Area enthalten ist (Du hast ja bisher noch überhaupt keine Staging Area aufgesetzt), und die `--cacheinfo` Option, weil Du eine Datei hinzufügst, die sich nicht in Deinem Arbeitsverzeichnis befindet (xxx hu? xxx), sondern in der Datenbank. Du gibst außerdem den Modus, SHA-1 Hash und den Dateinamen an: +Du kannst auch Deine eigenen Tree-Objekte anlegen. Git erzeugt Trees normalerweise, indem es die Inhalte der Staging-Area nimmt und als ein Tree-Objekt speichert. D.h., um ein Tree-Objekt anzulegen, musst Du zunächst einen Index (d.h. eine Staging-Area) aufbauen, indem Du einige Dateien hinzufügst. Um einen einzelnen Eintrag in den Index zu schreiben – z.B. die erste version der Datei test.txt – kannst Du den Plumbing-Befehl `git update-index` verwenden, der eine frühere Version dieser Datei künstlich zu einer neuen Staging-Area hinzufügt. Du musst ihm die Option `--add` übergeben, weil die Datei bisher noch nicht in der Staging-Area enthalten ist (Du hast ja bisher noch überhaupt keine Staging-Area aufgesetzt), und die Option `--cacheinfo`, weil Du eine Datei hinzufügst, die sich nicht in Deinem Verzeichnis befindet, sondern in der Datenbank. Du gibst außerdem den Modus, SHA-1-Hash und den Dateinamen an: $ git update-index --add --cacheinfo 100644 \ 83baae61804e65cc73a7201a7252750c76066a30 test.txt -In diesem Fall gibst Du als Modus `100644` an, was bedeutet, dass es sich um eine normale Date handelt. Eine ausführbare Datei wäre dagegen `100755` und ein symbolischer Link `120000`. Der Modus entspricht normalen UNIX Datei Modi, ist aber weniger flexibel. Die drei genannten Modi sind die einzigen, die in in Git für Dateien (blobs) verwendet werden (es gibt allerdings noch weitere Modi für Verzeichnisse und Submodule xxx). +In diesem Fall gibst Du als Modus `100644` an, was bedeutet, dass es sich um eine normale Datei handelt. Eine ausführbare Datei wäre dagegen `100755` und ein symbolischer Link `120000`. Der Modus entspricht normalen UNIX-Datei-Modi, ist aber weniger flexibel. Die drei genannten Modi sind die einzigen, die in Git für Dateien (Blobs) verwendet werden (es gibt allerdings noch weitere Modi für Verzeichnisse und Submodule). -Jetzt kannst Du den Befehl `git write-tree` verwenden, um die Staging Area als Tree Objekt zu schreiben. Dazu brauchst Du die `-w` Option nicht angeben – `git write-tree` schreibt automatisch ein Tree Objekt für Einträge der Staging Area, für die es noch keinen Tree gibt: +Jetzt kannst Du den Befehl `git write-tree` verwenden, um die Staging-Area als Tree-Objekt zu schreiben. Dazu brauchst Du die `-w` Option nicht angeben – `git write-tree` schreibt automatisch ein Tree-Objekt für Einträge der Staging-Area, für die es noch keinen Tree gibt: $ git write-tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579 @@ -193,14 +193,14 @@ Jetzt kannst Du den Befehl `git write-tree` verwenden, um die Staging Area als T -Um zu überprüfen, dass es wirklich ein Tree Objekt gibt: +Um zu überprüfen, ob es sich wirklich um ein Tree-Objekt handelt: $ git cat-file -t d8329fc1cc938780ffdd9f94e0d364e0ea74f579 tree -Jetzt erzeugen wir einen neuen Tree mit der zweiten Version der test.txt Datei sowie eine neue Datei: +Jetzt erzeugen wir einen neuen Tree mit der zweiten Version der Datei test.txt sowie einer neuen Datei: $ echo 'new file' > new.txt $ git update-index test.txt @@ -208,7 +208,7 @@ Jetzt erzeugen wir einen neuen Tree mit der zweiten Version der test.txt Datei s -Die Staging Area enthält jetzt eine neue Version der test.txt Datei sowie die neue Datei new.txt. Speichern wir diesen Tree (d.h. den gegenwärtigen Status der Staging Area bzw. des Index als Tree Objekt) und schauen ihn uns an: +Die Staging-Area enthält jetzt eine neue Version der Datei test.txt sowie die neue Datei new.txt. Speichern wir diesen Tree (d.h. den gegenwärtigen Status der Staging-Area bzw. des Index als Tree-Objekt) und schauen ihn uns an: $ git write-tree 0155eb4229851634a0f03eb265b69f5a2d56f341 @@ -218,7 +218,7 @@ Die Staging Area enthält jetzt eine neue Version der test.txt Datei sowie die n -Beachte, dass das Tree Objekt zwei Datei Einträge hat und dass der SHA-1 Hash der test.txt Datei noch derselbe „Version 2“ Hash ist wie zuvor (`1f7a7a`). Fügen wir jetzt den ersten Tree als ein Unterverzeichnis is diesem hier ein. Du kannst einen Tree mit `git read-tree` in die Staging Area einlesen. In diesem Fall können wir einen bereits existierenden Tree als einen Untertree zur Staging Area hinzufügen, indem wir die `--prefix` Option verwenden: +Beachte, dass das Tree-Objekt beide Datei-Einträge hat und dass der SHA-1-Hash der Datei test.txt noch derselbe „Version 2“-Hash ist wie zuvor (`1f7a7a`). Fügen wir jetzt den ersten Tree als ein Unterverzeichnis in diesem hier ein. Du kannst einen Tree mit `git read-tree` in die Staging-Area einlesen. In diesem Fall können wir einen bereits existierenden Tree als einen Untertree zur Staging-Area hinzufügen, indem wir die Option `--prefix` verwenden: $ git read-tree --prefix=bak d8329fc1cc938780ffdd9f94e0d364e0ea74f579 $ git write-tree @@ -230,30 +230,30 @@ Beachte, dass das Tree Objekt zwei Datei Einträge hat und dass der SHA-1 Hash d -Wenn Du ein Arbeitsverzeichnis aus diesem neuen Tree Objekt auschecken würdest, würdest Du zwei Dateien im Hauptverzeichnis und ein Unterverzeichnis mit dem Namen `bak` erhalten, in dem sich die erste Version der Datei test.txt befindet. Du kannst Dir die Daten, die Git für diese Strukturen speichert, in etwa wie in Bild 9-2 vorstellen. +Wenn Du ein Arbeitsverzeichnis aus diesem neuen Tree-Objekt auschecken würdest, würdest Du zwei Dateien im Hauptverzeichnis und ein Unterverzeichnis mit dem Namen `bak` erhalten, in dem sich die erste Version der Datei test.txt befindet. Du kannst Dir die Daten, die Git für diese Strukturen speichert, in etwa wie in Bild 9-2 vorstellen. Insert 18333fig0902.png -Bild 9-2. Die Datenstruktur des gegenwärtigen Git Repositories. +Bild 9-2. Die Datenstruktur des gegenwärtigen Git-Repositorys. ### Objekte committen ### -Du hast jetzt drei Trees, die verschiedene Snapshots Deines Projektes spezifizieren (xxx), die Du nachverfolgen willst. Das ursprüngliche Problem besteht aber weiterhin: Du musst alle drei SHA-1 Hash Werte erinnern, um wieder an die Snapshots zu kommen. Ebenso fehlen Dir die Informationen darüber, wer die Snapshots gespeichert hat, wann sie gespeichert wurden und warum. Dies sind die drei Hauptinformationen, die ein Commit Objekt für uns speichert. +Du hast jetzt drei Trees, die verschiedene Snapshots Deines Projektes spezifizieren, die Du nachverfolgen willst. Das ursprüngliche Problem besteht aber weiterhin: Du musst Dir alle drei SHA-1-Hashwerte merken, um wieder an die Snapshots zu kommen. Ebenso fehlen Dir die Informationen darüber, wer die Snapshots gespeichert hat, wann sie gespeichert wurden und warum. Dies sind die drei Hauptinformationen, die ein Commit-Objekt für uns speichert. -Um ein Commit Objekt anzulegen, verwendest Du den Befehl `git commit-tree`, spezifizierst einen einzelnen Tree SHA-1 Hash und welche Commit Objekte (sofern vorhanden) die direkten Vorgänger sind. Fangen wir damit an, den ersten Tree, den Du angelegt hast, zu committen: +Um ein Commit-Objekt anzulegen, verwendest Du den Befehl `git commit-tree`, spezifizierst den SHA-1-Hash eines einzelnen Trees und welche Commit-Objekte (sofern vorhanden) die direkten Vorgänger sind. Fangen wir damit an, den ersten Tree, den Du angelegt hast, einzuchecken: $ echo 'first commit' | git commit-tree d8329f fdf4fc3344e67ab068f836878b6c4951e3b15f3d -Du kannst diesen Commit jetzt mit `git cat-file` nachschlagen: +Du kannst Dir dann dieses neue Commit-Objekt mit `cat-file` anschauen: $ git cat-file -p fdf4fc3 tree d8329fc1cc938780ffdd9f94e0d364e0ea74f579 @@ -264,11 +264,11 @@ Du kannst diesen Commit jetzt mit `git cat-file` nachschlagen: -Das Format für ein Commit Objekt ist einfach: es besteht aus dem toplevel Tree für den Snapshot des Projektes zum gegebenen Zeitpunkt, die Autor und ggf. Committer Information (jeweils entsprechend Deiner `user.name` und `user.email` Konfiguration) und dem Timestamp. Dann folgen eine leere Zeile und die Commit Meldung. +Das Format für ein Commit-Objekt ist einfach: es besteht aus dem obersten Tree für den Snapshot des Projektes zum gegebenen Zeitpunkt, die Autoren- und ggf. Committer-Information (jeweils entsprechend Deiner `user.name`- und `user.email`-Konfiguration) und dem aktuellen Zeitstempel. Dann folgen eine leere Zeile und die Commit-Nachricht. -Als nächstes speichern wir die beiden anderen Commit Objekte und referenzieren jeweils den vorhergehenden Commit: +Als Nächstes speichern wir die beiden anderen Commit-Objekte und referenzieren jeweils den vorhergehenden Commit: $ echo 'second commit' | git commit-tree 0155eb -p fdf4fc3 cac0cab538b970a37ea1e769cbbde608743bc96d @@ -277,7 +277,7 @@ Als nächstes speichern wir die beiden anderen Commit Objekte und referenzieren -Jedes der drei Commit Objekte zeigt auf einen der drei Snapshopt Trees, die Du zuvor gespeichert hattest. Es mag Dich überraschen, aber Du hast jetzt bereits eine vollständige Git Historie, die Du mit dem `git log` inspizieren kannst, indem Du den letzten Commit SHA-1 Hash angibst: +Jedes der drei Commit-Objekte zeigt auf einen der drei Snapshot-Trees, die Du zuvor gespeichert hattest. Es mag Dich überraschen, aber Du hast jetzt bereits eine vollständige Git-Historie, die Du mit dem Befehl `git log` inspizieren kannst, indem Du den SHA-1-Hash des letzten Commits angibst: $ git log --stat 1a410e commit 1a410efbd13591db07496601ebc7a059dd55cfe9 @@ -310,7 +310,7 @@ Jedes der drei Commit Objekte zeigt auf einen der drei Snapshopt Trees, die Du z -Fantastisch, oder? Du hast jetzt sämtliche low-level Operationen durchgeführt, die eine vollständige Git Historie aufbauen, ohne aber irgendwelche Git Frontend Befehle (xxx) zu verwenden. Im wesentlichen ist das derselbe Prozess, der im Hintergrund stattfindet, wenn Du die Befehle `git add` und `git commit` ausführst. Sie speichern Blobs für die Dateien, die Du hinzugefügt oder geändert hast, aktualisieren den Index (d.h. die Staging Area), speichern Trees und legen Commit Objekte an, die die toplevel Trees und Commits referenzieren, die ihnen unmittelbar vorhergingen. Diese drei Hauptobjekte – Blob, Tree und Commit – werden zunächst als separate Dateien im `.git/objects` Verzeichnis gespeichert. Hier ist eine Liste aller Objekte, die sich in unserem Beispiel Repository jetzt in der Datenbank befinden – jeweils mit einem Kommentar darüber, was sie speichern: +Fantastisch, oder? Du hast jetzt sämtliche Low-Level-Operationen durchgeführt, die eine vollständige Git-Historie aufbauen, ohne aber irgendwelche Frontend-Befehle von Git zu verwenden. Im Wesentlichen ist das derselbe Prozess, der im Hintergrund stattfindet, wenn Du die Befehle `git add` und `git commit` ausführst. Sie speichern Blobs für die Dateien, die Du hinzugefügt oder geändert hast, aktualisieren den Index (d.h. die Staging-Area), speichern Trees und legen Commit Objekte an, die die obersten Trees sowie die Commits referenzieren, die ihnen unmittelbar vorhergingen. Diese drei Hauptobjekte – Blob, Tree und Commit – werden zunächst als separate Dateien im Verzeichnis `.git/objects` gespeichert. Hier ist eine Liste aller Objekte, die sich in unserem Beispiel-Repository jetzt in der Datenbank befinden – jeweils mit einem Kommentar darüber, was sie speichern: $ find .git/objects -type f .git/objects/01/55eb4229851634a0f03eb265b69f5a2d56f341 # tree 2 @@ -326,19 +326,19 @@ Fantastisch, oder? Du hast jetzt sämtliche low-level Operationen durchgeführt, -Wenn man all diese Zeiger auflöst, erhält man einen Objekt Graphen wie den folgenden (Bild 9-3). +Wenn man all diese internen Zeiger nachverfolgt, erhält man einen Objekt-Graphen wie den folgenden (Bild 9-3). Insert 18333fig0903.png -Bild 9-3. Die Objekte im Beispielrepository. +Bild 9-3. Alle Objekte in Deinem Git-Repository. -### Objekt Speicher ### +### Objekt-Speicher ### -Wir haben kurz erwähnt, dass zusammen mit einem Inhalt ein Header gespeichert wird. Schauen wir uns also genauer an, wie genau Git Objekte speichert. Du wirst sehen, wie ein Blob Objekt – in diesem Fall der String „what is up, doc?“ (xxx übersetzen? xxx) gespeichert wird. Dazu nuten wir den interaktiven Ruby Modus, den Du mit dem `irb` Befehl starten kannst: +Ich habe bereits erwähnt, dass zusammen mit dem jeweiligen Inhalt ein Header gespeichert wird. Schauen wir uns also genauer an, wie genau Git Objekte speichert. Du wirst sehen, wie ein Blob-Objekt – in diesem Fall die Zeichenkette „what is up, doc?“ gespeichert wird. Dazu nutzen wir den interaktiven Ruby-Modus, den Du mit dem Befehl `irb` starten kannst: $ irb >> content = "what is up, doc?" @@ -346,14 +346,14 @@ Wir haben kurz erwähnt, dass zusammen mit einem Inhalt ein Header gespeichert w -Git erzeugt einen Header, der mit dem Objekt Typ beginnt, in diesem Fall ist das ein Blob. Dann folgt ein Leerzeichen, die Anzahl der Zeichen des Inhalts und schließlich ein Nullbyte. +Git erzeugt einen Header, der mit dem Objekttyp beginnt, in diesem Fall ist das ein Blob. Dann folgt ein Leerzeichen, die Anzahl der Zeichen des Inhalts und schließlich ein Nullbyte. >> header = "blob #{content.length}\0" => "blob 16\000" -Git fügt diesen Header mit dem ursprünglichen Inhalt zusammen und kalkuliert aus dem Ergebnis die SHA-1 Prüfsumme (Hash). Du kannst einen SHA-1 Hash in Ruby berechnen, indem Du die SHA1 digest Bibliothek mit `require` einbindest und dann `Digest::SHA1.hexdigest()` mit dem String ausführst: +Git fügt diesen Header mit dem ursprünglichen Inhalt zusammen und kalkuliert aus dem Ergebnis die SHA-1-Prüfsumme. Du kannst einen SHA-1-Hash in Ruby berechnen, indem Du die SHA1-Digest-Bibliothek mit `require` einbindest und dann `Digest::SHA1.hexdigest()` mit der Zeichenkette ausführst: >> store = header + content => "blob 16\000what is up, doc?" @@ -364,7 +364,7 @@ Git fügt diesen Header mit dem ursprünglichen Inhalt zusammen und kalkuliert a -Git komprimiert den neuen Inhalt (d.h. inklusive des Headers) mit zlib. In Ruby kannst Du dazu die zlib Bibliothek verwenden, indem Du wiederum zuerst die Bibliothek mit `require` einbindest und dann `Zlib::Deflate.deflate()` mit dem Inhalt aufrufst: +Git komprimiert den neuen Inhalt (d.h. inklusive des Headers) mit zlib. In Ruby kannst Du dazu die zlib-Bibliothek verwenden, indem Du wiederum zuerst die Bibliothek mit `require` einbindest und dann `Zlib::Deflate.deflate()` mit dem Inhalt aufrufst: >> require 'zlib' => true @@ -373,7 +373,7 @@ Git komprimiert den neuen Inhalt (d.h. inklusive des Headers) mit zlib. In Ruby -Schließlich schreibst Du den zlib-komprimierten Inhalt in eine Datei auf der Festplatte. Dazu bestimmst Du den Pfad, an den die Datei gespeichert wird (die ersten beiden Zeichen für das Unterverzeichnis und die verbleibenden 38 Zeichen für den Dateinamen). In Ruby kannst Du die Funktion `FileUtils.mkdir_p()` verwenden, um Unterverzeichnisse anzulegen, die noch nicht existieren. Dann öffnest die Datei mit `File.open()` und schreibst den komprimierten Inhalt mit `write()` in die Datei: +Schließlich schreibst Du den zlib-komprimierten Inhalt in eine Datei auf der Festplatte. Dazu bestimmst Du den Pfad, an den die Datei gespeichert wird (die ersten beiden Zeichen für das Unterverzeichnis und die verbleibenden 38 Zeichen für den Dateinamen). In Ruby kannst Du die Funktion `FileUtils.mkdir_p()` verwenden, um Unterverzeichnisse anzulegen, die noch nicht existieren. Dann öffnest Du die Datei mit `File.open()` und schreibst den komprimierten Inhalt mit `write()` in die Datei: >> path = '.git/objects/' + sha1[0,2] + '/' + sha1[2,38] => ".git/objects/bd/9dbf5aae1a3862dd1526723246b20206e5fc37" @@ -386,18 +386,18 @@ Schließlich schreibst Du den zlib-komprimierten Inhalt in eine Datei auf der Fe -Das ist alles – Du hast jetzt ein valides Git Blob Objekt geschrieben. Git Objekte werden immer in dieser Weise gespeichert, lediglich mit verschiedenen Typen, d.h. anstelle des Strings „blob“ wird der Header mit „commit“ oder „tree“ anfangen. Außerdem sind Commit und Tree Inhalte auf eine sehr spezifische Weise formatiert, während Blobs beliebige Inhalte sein können. +Das ist alles – Du hast jetzt ein gültiges Blob-Objekt geschrieben. Git-Objekte werden immer in dieser Weise gespeichert, lediglich mit verschiedenen Typen, d.h. anstelle der Zeichenkette „blob“ wird der Header mit „commit“ oder „tree“ anfangen. Außerdem sind Commit- und Tree-Inhalte auf eine sehr spezifische Weise formatiert, während Blobs beliebige Inhalte sein können. -## Git Referenzen ## +## Git-Referenzen ## -Du kannst Befehle wie `git log 1a410e` ausführen, um die Commit Historie zu inspizieren, aber dazu musst Du Dir jeweils merken, dass `1a410e` der jeweils letzte Commit ist. Um diese SHA-1 Hashes mit einfacheren, verständlichen Namen zu referenzieren, verwendet Git weitere Dateien, in denen die Namen für Hashes gespeichert sind. +Du kannst Befehle wie `git log 1a410e` ausführen, um die Commit-Historie zu inspizieren, aber dazu musst Du Dir jeweils merken, dass `1a410e` der jeweils letzte Commit ist. Um diese SHA-1-Hashes mit einfacheren, verständlichen Namen zu referenzieren, verwendet Git weitere Dateien, in denen die Namen für Hashes gespeichert sind. -Diese Namen werden in Git intern als „references“ oder „refs“ bezeichnet. Du kannst diese Dateien, die SHA-1 Hashes enthalten, im `.git/refs` Verzeichnis finden. In unserem gegenwärtigen Projekt enthält dieses Verzeichnis noch keine Dateien, aber eine simple Verzeichnisstruktur: +Diese Namen werden in Git intern als „references“ oder „refs“ (also Referenz bzw. Verweis) bezeichnet. Du kannst diese Dateien, die SHA-1-Hashes enthalten, im Verzeichnis `.git/refs` finden. In unserem gegenwärtigen Projekt enthält dieses Verzeichnis noch keine Dateien, aber eine simple Verzeichnisstruktur: $ find .git/refs .git/refs @@ -408,13 +408,13 @@ Diese Namen werden in Git intern als „references“ oder „refs“ bezeichnet -Um jetzt eine neue Referenz anzulegen, die Dir dabei hilft, Dich zu erinnern, wo sich Dein letzten Commit befindet, könntest Du, technisch gesehen, Folgendes tun: +Um jetzt eine neue Referenz anzulegen, die Dir dabei hilft, Dich zu erinnern, wo sich Dein letzter Commit befindet, könntest Du, technisch gesehen, Folgendes tun: $ echo "1a410efbd13591db07496601ebc7a059dd55cfe9" > .git/refs/heads/master -Jetzt kannst Du diese „head“ Referenz anstelle des SHA-1 Wertes in allen möglichen Git Befehlen verwenden: +Jetzt kannst Du diese „head“-Referenz anstelle des SHA-1-Wertes in allen möglichen Git-Befehlen verwenden: $ git log --pretty=oneline master 1a410efbd13591db07496601ebc7a059dd55cfe9 third commit @@ -423,13 +423,13 @@ Jetzt kannst Du diese „head“ Referenz anstelle des SHA-1 Wertes in allen mö -Allerdings ist es nicht empfehlenswert, die Referenz Dateien direkt zu bearbeiten. Git stellt einen sichereren Befehl dafür zur Verfügung, den Befehl `git update-ref`: +Allerdings ist es nicht empfehlenswert, die Referenz-Dateien direkt zu bearbeiten. Git stellt einen sichereren Befehl dafür zur Verfügung, den Befehl `git update-ref`: $ git update-ref refs/heads/master 1a410efbd13591db07496601ebc7a059dd55cfe9 -Im Prinzip ist das alles, was einen Branch in Git ausmacht: ein simpler Zeiger oder eine Referenz auf den jeweiligen Kopf (xxx head xxx) einer Serie von Commits (xxx ??? xxx). Um einen neuen Branch anzulegen, der vom zweiten Commit aus verzweigt, kannst Du folgendes tun: +Im Prinzip ist das alles, was einen Branch in Git ausmacht: ein simpler Zeiger oder eine Referenz auf den jeweiligen Head einer Arbeitsreihe. Um einen neuen Branch anzulegen, der vom zweiten Commit aus verzweigt, kannst Du Folgendes tun: $ git update-ref refs/heads/test cac0ca @@ -443,23 +443,23 @@ Dein Branch beginnt jetzt beim zweiten Commit: -Die Git Datenbank unseres Beispielrepositories ist jetzt wie folgt strukturiert: +Die Git-Datenbank unseres Beispiel-Repositorys ist jetzt wie folgt strukturiert: Insert 18333fig0904.png -Bild 9-4. Git Verzeichnis Objekte mit Branch Head Referenzen. +Bild 9-4. Git-Verzeichnis-Objekte mit Branch-Head-Referenzen. -Wenn Du Befehle wie `git branch (branchname)` verwendest, führt Git intern im wesentlichen den `update-ref` Befehl aus, um den SHA-1 Hash des letzten Commits des jeweils gegenwärtigen Branches mit dem gegebenen Namen zu referenzieren. +Wenn Du Befehle wie `git branch (Branch-Name)` verwendest, führt Git intern im Wesentlichen den Befehl `update-ref` aus, um den SHA-1-Hash des letzten Commits des jeweils gegenwärtigen Branches mit dem gegebenen Namen zu referenzieren. ### Der HEAD ### -Die Frage ist jetzt: wenn Du `git branch (branchname)` ausführst, woher weiß Git den SHA-1 des letzten Commits? Die Antwort ist: aus der HEAD Datei. Diese Datei ist eine symbolische Referenz auf den jeweiligen Branch, auf dem Du Dich gerade befindest. Mit „symbolischer Referenz“ meine ich, dass sie (anders als eine „normale“ Referenz) keinen SHA-1 Hash enthält, sondern statt dessen auf eine andere Referenz zeigt. Wenn Du die HEAD Datei ansiehst, findest Du normalerweise etwas wie: +Die Frage ist jetzt: Wenn Du `git branch (Branch-Name)` ausführst, woher weiß Git den SHA-1 des letzten Commits? Die Antwort ist: aus der Datei HEAD. Diese Datei ist eine symbolische Referenz auf den jeweiligen Branch, auf dem Du Dich gerade befindest. Mit „symbolischer Referenz“ meine ich, dass sie (anders als eine „normale“ Referenz) keinen SHA-1-Hash enthält, sondern stattdessen auf eine andere Referenz zeigt. Wenn Du Dir die Datei ansiehst, findest Du normalerweise etwas wie: $ cat .git/HEAD ref: refs/heads/master @@ -473,11 +473,11 @@ Wenn Du jetzt `git checkout test` ausführst, wird Git die Datei aktualisieren, -Wenn Du `git commit` ausführst, erzeugt Git das Commit Objekt und verwendet als Parent des Commit Objektes den jeweiligen Wert der Referenz auf die HEAD zeigt. +Wenn Du `git commit` ausführst, erzeugt Git das Commit-Objekt und verwendet als Parent des Commit-Objektes den jeweiligen Wert der Referenz, auf die HEAD zeigt. -Du kannst diese Datei manuell bearbeiten, aber es Git verfügt wiederum über einen sichereren Befehl, um das zu tun: `git symbolic-ref`. Du kannst den Wert des HEAD mit Hilfe des folgenden Befehls lesen: +Du kannst diese Datei manuell bearbeiten, aber wiederum verfügt Git über einen sichereren Befehl, um das zu tun: `git symbolic-ref`. Du kannst den Wert des HEAD mit Hilfe des folgenden Befehls lesen: $ git symbolic-ref HEAD refs/heads/master @@ -502,7 +502,7 @@ Du kannst den Befehl allerdings nicht verwenden, um eine Referenz außerhalb von -Wir haben jetzt Gits drei Haupt Objekttypen besprochen, aber es gibt noch einen vierten. Das Tag Objekt ist dem Commit Objekt sehr ähnlich: es enthält einen Tagger (xxx), ein Datum, eine Meldung und eine Referenz auf ein anderes Objekt. Der Hauptunterschied besteht darin, dass ein Tag Objekt auf einen Commit zeigt und nicht auf einen Tree. Ein Tag ist in dieser Hinsicht also ähnlich einem Branch, aber er bewegt sich nie, sondern zeigt immer auf denselben Commit und gibt ihm damit einen netteren Namen. +Wir haben jetzt Gits drei Haupt-Objekttypen besprochen, aber es gibt noch einen vierten. Das Tag-Objekt ist dem Commit-Objekt sehr ähnlich: es enthält den Autor des Tags, ein Datum, eine Meldung und eine Referenz auf ein anderes Objekt. Der Hauptunterschied besteht darin, dass ein Tag-Objekt auf einen Commit zeigt und nicht auf einen Tree. Ein Tag ist in dieser Hinsicht also ähnlich einem Branch, aber er bewegt sich nie, sondern zeigt immer auf denselben Commit und gibt ihm damit einen netteren Namen. @@ -512,20 +512,20 @@ Wie wir schon in Kapitel 2 besprochen haben, gibt es zwei Typen von Tags: „ann -Das ist alles, woraus ein einfacher Tag besteht: einem Branch, der sich nie bewegt. Ein annotierter Tag ist komplexer. Wenn Du einen annotierten Tag anlegst, erzeugt Git ein Tag Objekt und speichert eine Referenz, die darauf zeigt, statt direkt auf den Commit zu zeigen. Du kannst das sehen, wenn Du einen annotierten Tag anlegst (`-a` bewirkt, dass wir einen annotierten Tag erhalten): +Das ist alles, woraus ein einfacher Tag besteht: einem Branch, der sich nie bewegt. Ein annotierter Tag ist komplexer. Wenn Du einen annotierten Tag anlegst, erzeugt Git ein Tag-Objekt und speichert eine Referenz, die darauf zeigt, statt direkt auf den Commit zu zeigen. Du kannst das sehen, wenn Du einen annotierten Tag anlegst (`-a` bewirkt, dass wir einen annotierten Tag erhalten): $ git tag -a v1.1 1a410efbd13591db07496601ebc7a059dd55cfe9 -m 'test tag' -Das erzeugt den folgenden Objekt SHA-1 Hash: +Das erzeugt den folgenden Objekt SHA-1-Hash: $ cat .git/refs/tags/v1.1 9585191f37f7b0fb9444f35a9bf50de191beadc2 -Jetzt wendest Du den `git cat-file` Befehl auf diesen SHA-1 Hash an: +Jetzt wendest Du den Befehl `git cat-file` auf diesen SHA-1-Hash an: $ git cat-file -p 9585191f37f7b0fb9444f35a9bf50de191beadc2 object 1a410efbd13591db07496601ebc7a059dd55cfe9 @@ -537,20 +537,20 @@ Jetzt wendest Du den `git cat-file` Befehl auf diesen SHA-1 Hash an: -Beachte, dass der der `object` Wert auf den commit SHA-1 zeigt, den Du getaggt hast, und dass die `tags/v1.1` Referenz nicht direkt auf den Commit zeigt, sondern auf das Tag Objekt. In Git kannst Du jedes beliebige Objekt taggen. Im Git Quellcode z.B. befindet sich der öffentliche GPG Schlüssel des Projektbetreibers als ein Blob Objekt, sowie ein Tag, der darauf zeigt. Auf diese Weise kannst den Schlüssel so anzeigen, indem Du den folgenden Befehl im Git Quellcode Repository ausführst: +Beachte, dass der der Wert `object` auf den SHA-1 des Commits zeigt, den Du getaggt hast. Weiterhin muss der Eintrag nicht auf einen Commit zeigen. In Git kann man jedes beliebige Objekt taggen. Im Git-Quellcode befindet sich beispielweise der öffentliche GPG-Schlüssel des Projektbetreibers als ein Blob-Objekt, sowie ein Tag, der darauf zeigt. Du kannst Dir den öffentlichen Schlüssel anzeigen lassen, indem du den folgenden Befehl im Git-Quellcode-Repository ausführst: $ git cat-file blob junio-gpg-pub -Der Linux Kernel hat also ein Tag Objekt, das nicht auf einen Commit zeigt – der erste Tag (xxx) zeigt auf den ursprünglichen Tree mit dem Import des Quellcodes (xxx what? xxx). +Der Linux-Kernel hat auch ein Tag-Objekt, das nicht auf einen Commit zeigt – der erste erstellte Tag zeigt auf den anfänglichen Tree des Quelltext-Imports. ### Externe Referenzen ### -Der dritte Referenztyp ist die externe Referenz („remote reference“). Wenn Du einen externen Server („remote“) definierst und dorthin pushst, merkt sich Git den zuletzt gepushten Commit für jeden Branch im `refs/remotes` Verzeichnis. Bespielsweise fügst Du einen externen Server `origin` hinzu und pushst Deinen `master` Branch dorthin: +Der dritte Referenztyp ist die externe Referenz („remote reference“). Wenn Du einen externen Server („remote“) definierst und dorthin pushst, merkt sich Git den zuletzt gepushten Commit für jeden Branch im `refs/remotes` Verzeichnis. Bespielsweise fügst Du einen externen Server `origin` hinzu und pushst Deinen Branch `master` dorthin: $ git remote add origin git@github.com:schacon/simplegit-progit.git $ git push origin master @@ -563,7 +563,7 @@ Der dritte Referenztyp ist die externe Referenz („remote reference“). Wenn D -Dann kannst Du herausfinden, in welchem Zustand sich der `master` Branch auf dem `origin` Server zuletzt befand (d.h. als Du das letzte Mal mit ihm kommuniziert hast), indem Du die Datei `refs/remotes/origin/master` anschaust: +Dann kannst Du herausfinden, in welchem Zustand sich der Branch `master` auf dem Server `origin` zuletzt befand (d.h. als Du das letzte Mal mit ihm kommuniziert hast), indem Du Dir die Datei `refs/remotes/origin/master` anschaust: $ cat .git/refs/remotes/origin/master ca82a6dff817ec66f44342007202690a93763949 @@ -577,7 +577,7 @@ Externe Referenzen unterscheiden sich von Branches (`refs/heads`) hauptsächlich -Kommen wir noch einmal auf die Objekt Datenbank zurück, die Du für Dein Test Git Repository angelegt hast. Im Moment müsstest Du 11 Objekte haben: 4 Blobs, 3 Trees, 3 Commits und 1 Tag: +Kommen wir noch einmal auf die Objekt-Datenbank zurück, die Du für Dein Test-Repository angelegt hast. Im Moment müsstest Du 11 Objekte haben: 4 Blobs, 3 Trees, 3 Commits und 1 Tag: $ find .git/objects -type f .git/objects/01/55eb4229851634a0f03eb265b69f5a2d56f341 # tree 2 @@ -594,9 +594,9 @@ Kommen wir noch einmal auf die Objekt Datenbank zurück, die Du für Dein Test G -Git komprimiert die Inhalte dieser Dateien mit zlib und Du hast nicht sonderlich viele davon, sodass die Gesamtgröße der Dateien gerade mal 925 Bytes beträgt. Wir wollen ein anderes interessantes Feature von Git demonstrieren, und dazu müssen wir eine größere Datei hinzufügen, z.B. die `repo.rb` Datei aus dem Grit Repository, das Du schon verwendet hast. Diese Datei ist eine etwa 12K große Quellcode Datei: +Git komprimiert die Inhalte dieser Dateien mit zlib und Du hast nicht sonderlich viele davon, sodass die Gesamtgröße der Dateien gerade mal 925 Bytes beträgt. Wir wollen ein anderes interessantes Feature von Git demonstrieren, und dazu müssen wir eine größere Datei hinzufügen, z.B. die `repo.rb` Datei aus der Grit-Bibliothek, die Du schon verwendet hast. Diese Datei ist eine etwa 12K große Quelltext-Datei: - $ curl https://raw.github.com/mojombo/grit/master/lib/grit/repo.rb > repo.rb + $ curl -L https://raw.github.com/mojombo/grit/master/lib/grit/repo.rb > repo.rb $ git add repo.rb $ git commit -m 'added repo.rb' [master 484a592] added repo.rb @@ -607,7 +607,7 @@ Git komprimiert die Inhalte dieser Dateien mit zlib und Du hast nicht sonderlich -Wenn Du Dir den resultierenden Tree anschaust, findest Du den SHA-1 Hash, den die Datei `repo.rb` für das Blob Objekt erhalten hat: +Wenn Du Dir den resultierenden Tree anschaust, findest Du den SHA-1-Hash, den die Datei `repo.rb` für das Blob-Objekt erhalten hat: $ git cat-file -p master^{tree} 100644 blob fa49b077972391ad58037050f2a75f74e3671e92 new.txt @@ -618,12 +618,12 @@ Wenn Du Dir den resultierenden Tree anschaust, findest Du den SHA-1 Hash, den di Jetzt kannst Du mit `git cat-file` sehen, wie groß das Objekt ist: - $ Du -b .git/objects/9b/c1dc421dcd51b4ac296e3e5b6e2a99cf44391e + $ du -b .git/objects/9b/c1dc421dcd51b4ac296e3e5b6e2a99cf44391e 4102 .git/objects/9b/c1dc421dcd51b4ac296e3e5b6e2a99cf44391e -Als nächste ändern wir die Datei ein bisschen, um zu sehen, was passiert: +Als Nächstes ändern wir die Datei ein bisschen, um zu sehen, was passiert: $ echo '# testing' >> repo.rb $ git commit -am 'modified repo a bit' @@ -643,7 +643,7 @@ Wenn Du jetzt den Tree anschaust, der durch den Commit angelegt wurde, findest D Das Blob ist ein anderes, d.h. obwohl Du lediglich eine einzige Zeile an das Ende einer 400 Zeilen langen Datei angehängt hast, speichert Git den Inhalt jetzt als ein ganz neues Objekt: - $ Du -b .git/objects/05/408d195263d853f09dca71d55116663690c27c + $ du -b .git/objects/05/408d195263d853f09dca71d55116663690c27c 4109 .git/objects/05/408d195263d853f09dca71d55116663690c27c @@ -652,7 +652,7 @@ Du hast jetzt zwei fast identische 12K große Objekte auf Deiner Festplatte. Wä -Tatsächlich kann Git das. Das ursprüngliche Format, in dem Git Objekte in der Datenbank speichert wird als „freies Objekt Format“ („loose object format“) bezeichnet. Hin und wieder packt Git allerdings eine Reihe solcher Objekte in eine einzige binäre Datei zusammen, um Platz zu sparen und effizienter zu arbeiten. Eine solche Datei wird als „packfile“ bezeichnet. Git tut das immer dann, wenn zu viele freie Objekte vorhanden sind, wenn Du den Befehl `git gc` manuell ausführst oder wenn Du auf einen externen Server pushst. Schauen wir uns also an, was passiert, wenn wir manuell `git gc` ausführen: +Tatsächlich kann Git das. Das ursprüngliche Format, in dem Git Objekte in der Datenbank speichert, wird als „freies Objekt-Format“ („loose object format“) bezeichnet. Hin und wieder packt Git allerdings eine Reihe solcher Objekte in eine einzige binäre Datei zusammen, um Platz zu sparen und effizienter zu arbeiten. Eine solche Datei wird als „packfile“ bezeichnet. Git tut das immer dann, wenn zu viele freie Objekte vorhanden sind, wenn Du den Befehl `git gc` manuell ausführst oder wenn Du auf einen externen Server pushst. Schauen wir uns also an, was passiert, wenn wir manuell `git gc` ausführen: $ git gc Counting objects: 17, done. @@ -663,7 +663,7 @@ Tatsächlich kann Git das. Das ursprüngliche Format, in dem Git Objekte in der -Wenn Du das Objekt Verzeichnis anschaust, siehst Du, dass die meisten Objekte jetzt fehlen und dass stattdessen zwei neue Objekte aufgetaucht sind: +Wenn Du das Objekt-Verzeichnis anschaust, siehst Du, dass die meisten Objekte jetzt fehlen und dass stattdessen zwei neue Objekte aufgetaucht sind: $ find .git/objects -type f .git/objects/71/08f7ecb345ee9d0084193f147cdad4d2998293 @@ -674,7 +674,7 @@ Wenn Du das Objekt Verzeichnis anschaust, siehst Du, dass die meisten Objekte je -Die verbleibenden Objekte sind diejenigen Blobs, die nicht von irgendeinem Commit referenziert werden – in diesem Fall sind das die „what is up, doc?“ und „test content“ Beispielblobs, die wir zuvor gespeichert hatten: weil wir sie nie zu irgendeinem Commit hinzugefügt haben, werden sie als „dangling“ (xxx) betrachtet und nicht im Packfile zusammengepackt. +Die verbleibenden Objekte sind diejenigen Blobs, die nicht von irgendeinem Commit referenziert werden – in diesem Fall sind das die Beispielblobs „what is up, doc?“ und „test content“, die wir zuvor gespeichert hatten. Weil wir sie nie zu irgendeinem Commit hinzugefügt haben, werden sie als „dangling“ (wörtlich: herumbaumelnd) betrachtet und nicht im Packfile zusammengepackt. @@ -709,7 +709,7 @@ Wie stellt Git das genau an? Wenn Git Objekte zusammen packt, sucht es nach Date -Du erinnerst dich, dass der `9bc1d` Blob die erste Version der `repo.rb` Datei ist. Dieser Blob referenziert jetzt den `05408` Blob, der die zweite Version der Datei ist. Die dritte Spalte der Ausgabe ist die Größe des Objektes im Packfile. Wir können also sehen, dass `05408` 12K in Anspruch nimmt, `9bc1d` aber nur 7 Bytes. Das bedeutet also, dass die zweite Version diejenige ist, die vollständig, während die ursprüngliche, erste Version als Delta gespeichert wird! Der Grund dafür ist, dass Du höchstwahrscheinlich einen schnelleren Zugriff auf die jeweils neuesten Dateien brauchst. +Du erinnerst dich, dass der Blob `9bc1d` die erste Version der `repo.rb`-Datei ist. Dieser Blob referenziert jetzt den Blob`05408`, der die zweite Version der Datei ist. Die dritte Spalte der Ausgabe ist die Größe des Objektes im Packfile. Wir können also sehen, dass `05408` 12K in Anspruch nimmt, `9bc1d` aber nur 7 Bytes. Das bedeutet also, dass die zweite Version diejenige ist, die vollständig, während die ursprüngliche, erste Version als Delta gespeichert wird! Der Grund dafür ist, dass Du höchstwahrscheinlich einen schnelleren Zugriff auf die jeweils neuesten Dateien brauchst. @@ -718,16 +718,16 @@ Außerdem ist toll, dass ein Repository jederzeit neu gepackt werden kann. Git m ## Die Refspec ## - + + -In diesem Buch haben wir bisher einfache Mappings von externen Branches auf lokale Referenzen verwendet. Sie können aber auch durchaus komplex sein. Nehmen wir an, Du hast ein externes Repository wie folgt definiert: +In diesem Buch haben wir bisher einfache Zuweisungen von externen Branches auf lokale Referenzen verwendet. Sie können aber auch durchaus komplex sein. Nehmen wir an, Du hast ein Remote-Repository wie folgt definiert: $ git remote add origin git@github.com:schacon/simplegit-progit.git -Das fügt eine Sektion in Deine `.git/config` Datei hinzu, die Deinen lokalen Namen des externen Repositories (`origin`), dessen URL und die Refspec spezifiziert, mit der neue Daten heruntergeladen werden. +Das fügt eine Sektion in Deine `.git/config`-Datei hinzu, die Deinen lokalen Namen des externen Repositorys (`origin`), dessen URL und die Refspec spezifiziert, mit der neue Daten heruntergeladen werden. [remote "origin"] url = git@github.com:schacon/simplegit-progit.git @@ -735,11 +735,11 @@ Das fügt eine Sektion in Deine `.git/config` Datei hinzu, die Deinen lokalen Na -Das Format der Refspec besteht aus einem optionalen `+` gefolgt von `:`, wobei `` ein Pattern für Referenzen auf der Remote Seite ist, und `` angibt, wohin diese Referenzen lokal geschrieben werden. Das `+` weist Git an, die Referenz zu mergen, wenn sie nicht mit einem fast-forward aktualisiert werden kann. +Das Format der Refspec besteht aus einem optionalen `+` gefolgt von `:`, wobei `` ein Muster für Referenzen auf der Remote-Seite ist, und `` angibt, wohin diese Referenzen lokal geschrieben werden. Das `+` weist Git an, die Referenz zu mergen, wenn sie nicht mit einem Fast-forward aktualisiert werden kann. -Der Standard, der von `git remote add` automatisch eingerichtet wird, besteht darin, dass Git austomatisch alle Referenzen unter `refs/heads/` vom Server holt und sie lokal nach `refs/remotes/origin` speichert. D.h., wenn es auf dem Server einen `master` Branch gibt, kannst Du auf das Log dieses Branches wie folgt zugreifen: +Der Standard, der von `git remote add` automatisch eingerichtet wird, besteht darin, dass Git automatisch alle Referenzen unter `refs/heads/` vom Server holt und sie lokal nach `refs/remotes/origin` speichert. D.h., wenn es auf dem Server einen Branch `master` gibt, kannst Du auf das Log dieses Branches wie folgt zugreifen: $ git log origin/master $ git log remotes/origin/master @@ -751,19 +751,19 @@ Diese Varianten sind allesamt äquivalent, weil Git sie jeweils zu `refs/remotes -Wenn Du statt dessen willst, dass Git jeweils nur den `master` Branch herunterlädt und andere Branches auf dem Server ignoriert, kannst Du die `fetch` Zeile wie folgt ändern: +Wenn Du stattdessen willst, dass Git jeweils nur den Branch `master` herunterlädt und andere Branches auf dem Server ignoriert, kannst Du die `fetch`-Zeile wie folgt ändern: fetch = +refs/heads/master:refs/remotes/origin/master -Dies ist allerdings lediglich der Default Refspec Wert und Du kannst ihn auf der Kommandozeile jederzeit überschreiben. Z.B. um nur `master` branch vom Server lokal als `origin/mymaster` zu speichern, kannst Du folgendes ausführen: +Dies ist allerdings lediglich der Standardwert der Refspec und Du kannst ihn auf der Kommandozeile jederzeit überschreiben. Um zum Beispiel nur den Branch `master` vom Server lokal als `origin/mymaster` zu speichern, kannst Du Folgendes ausführen: $ git fetch origin master:refs/remotes/origin/mymaster -Du kannst auch mehrere Refspecs gleichzeitig spezifizieren. Z.B.: +Du kannst auch mehrere Refspecs gleichzeitig spezifizieren. Um mehrere Branches zu holen kannst du folgenden Befehl in die Kommandozeile eingeben: $ git fetch origin master:refs/remotes/origin/mymaster \ topic:refs/remotes/origin/topic @@ -771,13 +771,13 @@ Du kannst auch mehrere Refspecs gleichzeitig spezifizieren. Z.B.: ! [rejected] master -> origin/mymaster (non fast forward) * [new branch] topic -> origin/topic - + -I diesem Fall wurde ein Pull zurückgewiesen (xxx ist das nicht nur ein fetch? xxx), weil der Branch nicht mit einem simplen fast-forward aktualisiert werden konnte. Du kannst einen Merge erzwingen, indem Du der Refspec ein `+` voranstellst. +In diesem Fall wurde ein Pull zurückgewiesen, weil der Branch nicht mit einem simplen Fast-forward aktualisiert werden konnte. Du kannst einen Merge erzwingen, indem Du der Refspec ein `+` voranstellst. -Du kannst außerdem natürlich auch mehrere Refspecs in Deiner Konfiguration spezifizieren. Wenn Du z.B. immer die `master` und `experiment` Branches holen willst, fügst Du die folgenden Zeilen hinzu: +Du kannst außerdem natürlich auch mehrere Refspecs in Deiner Konfiguration spezifizieren. Wenn Du z.B. immer die Branches `master` und `experiment` holen willst, fügst Du die folgenden Zeilen hinzu: [remote "origin"] url = git@github.com:schacon/simplegit-progit.git @@ -786,13 +786,13 @@ Du kannst außerdem natürlich auch mehrere Refspecs in Deiner Konfiguration spe -Du kannst keine partiellen Glob Patterns verwenden, d.h. folgendes wäre ungültig: +Du kannst keine partiellen Glob-Muster verwenden, d.h. Folgendes wäre ungültig: fetch = +refs/heads/qa*:refs/remotes/origin/qa* -Allerdings kannst Du Namensräume verwenden, um etwas ähnliches zu erreichen. Nehmen wir an, Du hast ein QA Team, das regelmäßig verschiedene Branches pusht, und Du willst nun den master Branch und sämtliche Branches des QA Teams, aber keine anderen Branches haben. Dann kannst Du eine Config Sektion wie die folgende verwenden: +Allerdings kannst Du Namensräume verwenden, um etwas Ähnliches zu erreichen. Nehmen wir an, Du hast ein QA-Team, das regelmäßig verschiedene Branches pusht, und Du willst nun den Branch master und sämtliche Branches des QA-Teams, aber keine anderen Branches haben. Dann kannst Du eine Config-Sektion wie die folgende verwenden: [remote "origin"] url = git@github.com:schacon/simplegit-progit.git @@ -801,24 +801,24 @@ Allerdings kannst Du Namensräume verwenden, um etwas ähnliches zu erreichen. N -In einem großen Team mit einem komplexen Workflow, in dem ein QA Team, Entwickler und ein Integrations Team jeweils eigene Branches pushen, kann man auf diese Weise Branches einfach in Namensräume einteilen. +In einem großen Team mit einem komplexen Workflow, in dem ein QA-Team, Entwickler und ein Integrations-Team jeweils eigene Branches pushen, kann man auf diese Weise Branches einfach in Namensräume einteilen. ### Refspecs pushen ### -Wie aber legt das QA Team die Branches im `qa/` Namensraum ab? Das geht, indem man mit einer Refspec pusht. +Wie aber legt das QA-Team die Branches im `qa/` Namensraum ab? Das geht, indem man mit einer Refspec pusht. -Wenn das QA Team seinen `master` Branch in einem externen Repository als `qa/master` speichern will, kann es das wie folgt tun: +Wenn das QA-Team seinen Branch `master` in einem externen Repository als `qa/master` speichern will, kann es das wie folgt tun: $ git push origin master:refs/heads/qa/master -Um Git so zu konfigurieren, dass diese Refspec jedes mal automatisch für `git push origin` verwendet wird, kann man den `push` Wert in der Config Datei setzen: +Um Git so zu konfigurieren, dass diese Refspec jedes Mal automatisch für `git push origin` verwendet wird, kann man den `push` Wert in der Config-Datei setzen: [remote "origin"] url = git@github.com:schacon/simplegit-progit.git @@ -827,7 +827,7 @@ Um Git so zu konfigurieren, dass diese Refspec jedes mal automatisch für `git p -Auf diese Weise wird `git push origin` den lokalen Branch `master` als `qa/master` auf dem `origin` Server speichern. +Auf diese Weise wird `git push origin` den lokalen Branch `master` als `qa/master` auf dem Server `origin` speichern. ### Referenzen löschen ### @@ -840,52 +840,52 @@ Man kann Refspecs außerdem verwenden, um Referenzen aus einem externen Reposito -Das Refspec Format ist `:`. Wenn man den `` Teil weglässt, dann heißt das im obigen Beispiel, dass man den `topic` Branch auf dem `origin` Server auf „nichts“ setzt, d.h. also löscht. +Das Refspec Format ist `:`. Wenn man den Teil `` weglässt, dann heißt das im obigen Beispiel, dass man den Branch `topic` auf dem Server `origin` auf „nichts“ setzt, d.h. also löscht. -## Transfer Protokolle ## +## Transfer-Protokolle ## -Git kann Daten zwischen zwei Repositories im wesentlichen auf zwei Arten transportieren: über HTTP und über sogenannte smarte Protokolle, die mit `file://`, `ssh://` und `git://` verwendet werden. Die folgende Sektion gibt einen kurzen Überblick über diese Protokolle und wie sie funktionieren. +Git kann Daten zwischen zwei Repositorys im Wesentlichen auf zwei Arten transportieren: über HTTP und über sogenannte smarte Protokolle, die mit `file://`, `ssh://` und `git://` verwendet werden. Die folgende Sektion gibt einen kurzen Überblick über diese Protokolle und wie sie funktionieren. ### Das dumme Protokoll ### -Gits HTTP Transfer Protokoll wird oft auch als „dummes“ Protokoll bezeichnet, weil es auf der Server Seite keinen Git-spezifischen Code benötigt. Der `fetch` Prozess besteht aus einer Reihe von GET Requests, für die der Client Vorannahmen über das Layout des Git Repositories auf dem Server machen kann. Schauen wir uns den `http-fetch` Prozess der `simplegit` Bibliothek an: +Das HTTP-Transfer-Protokoll von Git wird oft auch als „dummes“ Protokoll bezeichnet, weil es auf der Server-Seite keinen Git-spezifischen Code benötigt. Der `fetch`-Prozess besteht aus einer Reihe von GET-Requests, für die der Client Vorannahmen über das Layout des Git-Repositorys auf dem Server machen kann. Schauen wir uns den `http-fetch`-Prozess der Bibliothek `simplegit` an: $ git clone http://github.com/schacon/simplegit-progit.git -Der Befehl lädt zunächst die `info/refs` Datei herunter. Diese Datei wird vom `update-server-info` Befehl geschrieben, den man als einen `post-receive` Hook einrichten muss, damit das HTTP Protokoll richtig funktionieren kann. +Der Befehl lädt zunächst die Datei `info/refs` herunter. Diese Datei wird vom Befehl `update-server-info` geschrieben, den man als einen `post-receive`-Hook einrichten muss, damit das HTTP-Protokoll richtig funktionieren kann. => GET info/refs ca82a6dff817ec66f44342007202690a93763949 refs/heads/master -Jetzt hat man eine Liste aller Referenzen und SHAs in diesem Repository. Als nächstes schaut man die HEAD Referenz nach, um zu wissen, was ausgecheckt werden muss: +Jetzt hat man eine Liste aller Referenzen und SHA-Prüfsummen in diesem Repository. Als nächstes schaut man die HEAD-Referenz nach, um zu wissen, was ausgecheckt werden muss: => GET HEAD ref: refs/heads/master -D.h., wenn wir mit dem Prozess fertig sind, wir müssen den `master` Branch auschecken. +D.h., wenn wir mit dem Prozess fertig sind, wir müssen den Branch `master` auschecken. -Wir können jetzt loslegen. Weil wir in der `info/refs` Datei der Commit `ca82a6` angegeben ist, fangen wir damit an, dieses Objekt herunter zu laden: +Wir können jetzt loslegen. Weil in der Datei `info/refs` der Commit `ca82a6` angegeben ist, fangen wir damit an, dieses Objekt herunterzuladen: => GET objects/ca/82a6dff817ec66f44342007202690a93763949 (179 bytes of binary data) -Wir erhalten also ein Objekt zurück. Dieses Objekt ist im losen Format auf dem Server gespeichert, und wir haben es über einen statischen HTTP GET Request herunter geladen. Jetzt können wir es mit zlib dekomprimieren, den Header entfernen und den Inhalt des Commits durchsehen: +Wir erhalten also ein Objekt zurück. Dieses Objekt ist im losen Format auf dem Server gespeichert, und wir haben es über einen statischen HTTP-GET-Request herunter geladen. Jetzt können wir es mit zlib dekomprimieren, den Header entfernen und den Inhalt des Commits durchsehen: $ git cat-file -p ca82a6dff817ec66f44342007202690a93763949 tree cfda3bf379e4f8dba8717dee55aab78aef7f4daf @@ -897,21 +897,21 @@ Wir erhalten also ein Objekt zurück. Dieses Objekt ist im losen Format auf dem -Als nächstes brauchen wir also zwei weitere Objekte: `cfda3b`, welches der Tree der Inhalte dieses Commits ist, und `085bb3`, den Commit Parent: +Als Nächstes brauchen wir also zwei weitere Objekte: `cfda3b`, welches der Tree der Inhalte dieses Commits ist, und `085bb3`, welches der übergeordnete Commit ist: => GET objects/08/5bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 (179 bytes of data) -Das gibt uns das nächste Commit Objekt. Versuchen wir, das Tree Objekt zu holen: +Das gibt uns das nächste Commit-Objekt. Versuchen wir, das Tree-Objekt zu holen: => GET objects/cf/da3bf379e4f8dba8717dee55aab78aef7f4daf (404 - Not Found) -Huch. Es sieht so aus als ob der Tree nicht im losen Format auf dem Server gespeichert ist, weshalb wir einen 404 Response („Not found“) erhalten. Dafür kann es verschiedene Gründe geben. Das Objekt könnte in einem anderen, alternativen Repository liegen, oder es könnte sich in einem Packfile befinden. Git sucht deshalb zunächst nach alternativen Repositories: +Huch. Es sieht so aus, als ob der Tree nicht im losen Format auf dem Server gespeichert ist, weshalb wir eine 404-Antwort („Not found“) erhalten. Dafür kann es verschiedene Gründe geben. Das Objekt könnte in einem anderen, alternativen Repository liegen, oder es könnte sich in einem Packfile befinden. Git sucht deshalb zunächst nach alternativen Repositories: => GET objects/info/http-alternates (empty file) @@ -921,14 +921,14 @@ Huch. Es sieht so aus als ob der Tree nicht im losen Format auf dem Server gespe -Wenn wir hier eine Liste alternativer URLs erhalten, schaut Git dort nach losen Dateien und Packfiles. Auf diese Weise können Repositories, die Forks von anderen Repositories sind, mit diesen Objekte im Dateisystem teilen. In unserem Fall sind allerdings keine Alternativen vorhanden, weshalb sich das gesuchte Objekt in einem Packfile befinden muss. Um die vorhandenen Packfiles nachzuschlagen, holt Git die `objects/info/packs` Datei, die eine entsprechende Auflistung enthält (und ebenfalls mit `update-server-info` erzeugt wird) +Wenn wir hier eine Liste alternativer URLs erhalten, schaut Git dort nach losen Dateien und Packfiles. Auf diese Weise können Repositorys, die Forks von anderen Repositorys sind, mit diesen Objekte im Dateisystem teilen. In unserem Fall sind allerdings keine Alternativen vorhanden, weshalb sich das gesuchte Objekt in einem Packfile befinden muss. Um die vorhandenen Packfiles nachzuschlagen, holt Git die `objects/info/packs` Datei, die eine entsprechende Auflistung enthält (und ebenfalls mit `update-server-info` erzeugt wird) => GET objects/info/packs P pack-816a9b2334da9953e530f27bcac22082a9f5b835.pack -Es gibt nur ein einziges Packfile auf dem Server, weshalb sich unser Objekt darin befinden muss. Aber wir prüfen die Index Datei, um sicher zu sein. Gäbe es mehrere Packfiles auf dem Server, könnten wir auf diese Weise herausfinden, welches Packfile das gesuchte Objekt enthält: +Es gibt nur ein einziges Packfile auf dem Server, weshalb sich unser Objekt darin befinden muss. Aber wir prüfen die Index-Datei, um sicher zu sein. Gäbe es mehrere Packfiles auf dem Server, könnten wir auf diese Weise herausfinden, welches Packfile das gesuchte Objekt enthält: => GET objects/pack/pack-816a9b2334da9953e530f27bcac22082a9f5b835.idx (4k of binary data) @@ -938,7 +938,7 @@ Es gibt nur ein einziges Packfile auf dem Server, weshalb sich unser Objekt dari -Nachdem wir jetzt den Packfile Index haben, können wir prüfen, ob sich unser Objekt darin befindet: der Index enthält eine Liste der SHA Hashes der Objekte, die sich im Packfile befinden und die jeweiligen Offsets dieser Objekte. Unser Objekt ist vorhanden, also laden wir das Packfile herunter: +Nachdem wir jetzt den Packfile-Index haben, können wir prüfen, ob sich unser Objekt darin befindet: der Index enthält eine Liste der SHA-Hashes der Objekte, die sich im Packfile befinden und die jeweiligen Offsets dieser Objekte. Unser Objekt ist vorhanden, also laden wir das Packfile herunter: => GET objects/pack/pack-816a9b2334da9953e530f27bcac22082a9f5b835.pack (13k of binary data) @@ -948,7 +948,7 @@ Nachdem wir jetzt den Packfile Index haben, können wir prüfen, ob sich unser O -Du hast jetzt das Tree Objekt, also kannst Du jetzt damit fortfahren, über die Commits zu iterieren. Sie sind in unserem Fall allesamt in dem Packfile enthalten, das Du gerade heruntergeladen hast. +Du hast jetzt das Tree-Objekt, also kannst Du jetzt damit fortfahren, über die Commits zu iterieren. Sie sind in unserem Fall allesamt in dem Packfile enthalten, das Du gerade heruntergeladen hast. @@ -968,22 +968,22 @@ Die Ausgabe des ganzen Vorgangs sieht dann in etwa so aus: walk a11bef06a3f659402fe7563abf99ad00de2209e6 -### Das Smart Protokoll (xxx) ### +### Das schlaue Protokoll ### -Die HTTP Methode ist simpel, aber sie ist auch ein bisschen ineffizient. Deshalb ist es üblicher, ein smartes Protokoll für den Datentransfer zu verwenden. Diese Protokolle umfassen serverseitige Prozesse, die Wissen über Git besitzen. Sie können lokale Daten lesen und herausfinden, was auf dem Client schon vorhanden ist oder fehlt und darauf zugeschnitten Daten generieren. Es gibt zwei Sets von Prozessen für den Datentransfer: ein Paar für den Upload und ein Paar für den Download von Daten. +Die HTTP-Methode ist simpel, aber sie ist auch ein bisschen ineffizient. Deshalb ist es üblicher, ein schlaues Protokoll für den Datentransfer zu verwenden. Diese Protokolle umfassen serverseitige Prozesse, die Wissen über Git besitzen. Sie können lokale Daten lesen und herausfinden, was auf dem Client schon vorhanden ist oder fehlt und darauf zugeschnittene Daten generieren. Es gibt zwei Sets von Prozessen für den Datentransfer: ein Paar für den Upload und ein Paar für den Download von Daten. #### Daten hochladen #### -Um Daten an einen serverseitigen Prozess zu schicken, verwendet Git die `send-pack` und `receive-pack` Prozesse. Der `send-pack` Prozess läuft auf dem Client und verbindet sich mit einem `receive-pack` Prozess auf dem Server. +Um Daten an einen serverseitigen Prozess zu schicken, verwendet Git die Prozesse `send-pack` und `receive-pack`. Der Prozess `send-pack` läuft auf dem Client und verbindet sich mit einem `receive-pack`-Prozess auf dem Server. -Nehmen wir z.B. an Du führst `git push origin master` in Deinem Projekt aus und `origin` ist als eine URL mit SSH Protokoll definiert. Git startet dann einen `send-pack` Prozess, der eine SSH Verbindung zum Server initiiert. Dieser versucht, via SSH auf dem Server einen Befehl wie den folgenden auszuführen: +Nehmen wir z.B. an, Du führst `git push origin master` in Deinem Projekt aus und `origin` ist als eine URL mit SSH-Protokoll definiert. Git startet dann einen `send-pack`-Prozess, der eine SSH-Verbindung zum Server initiiert. Dieser versucht, via SSH auf dem Server einen Befehl wie den folgenden auszuführen: $ ssh -x git@github.com "git-receive-pack 'schacon/simplegit-progit.git'" 005bca82a6dff817ec66f4437202690a93763949 refs/heads/master report-status delete-refs @@ -992,15 +992,15 @@ Nehmen wir z.B. an Du führst `git push origin master` in Deinem Projekt aus und -Der `git-receive-pack` Befehl antwortet dann mit jeweils einer Zeile pro Referenz, die er kennt – in diesem Fall sind das lediglich der `master` Branch und dessen SHA. Die erste Zeile listet außerdem Features, die der Server beherrscht (in unserem Fall `report-status` und `delete-refs`). +Der `git-receive-pack`-Befehl antwortet dann mit jeweils einer Zeile pro Referenz, die er kennt – in diesem Fall sind das lediglich der Branch `master` und dessen SHA-Prüfsumme. Die erste Zeile listet außerdem Features, die der Server beherrscht (in unserem Fall `report-status` und `delete-refs`). -Jede Zeile beginnt mit einem 4 Byte Hexadezimalzahl Wert, der angibt, wie lang der Rest der Zeile ist. Die erste Zeile beginnt mit 005b, d.h. dezimal 91. ALso ist der Rest der Zeile 91 Zeichen lang. Die nächste Zeile fängt mit 003e an, also dezimal 62. Die letzte Zeile ist 0000, was das Ende der Liste anzeigt. +Jede Zeile beginnt mit einem 4 Byte Hexadezimalzahl-Wert, der angibt, wie lang der Rest der Zeile ist. Die erste Zeile beginnt mit 005b, d.h. dezimal 91. ALso ist der Rest der Zeile 91 Zeichen lang. Die nächste Zeile fängt mit 003e an, also dezimal 62. Die letzte Zeile ist 0000, was das Ende der Liste anzeigt. -Nachdem Dein `send-pack` Prozess jetzt den Zustand des Servers kennt, kann er als nächstes evaluieren, welche Commits lokal, aber nicht auf dem Server vorhanden sind. der `send-pack` Prozess schickt diese Information für jede Referenz, auf die sich der `push` Befehl bezieht, an den `receive-pack` Prozess. Wenn Du beispielsweise den `master` Branch aktualisierst und einen `experiment` Branch hinzufügst, dann könnte die Antwort auf `send-pack` so aussehen: +Nachdem Dein `send-pack`-Prozess jetzt den Zustand des Servers kennt, kann er als nächstes evaluieren, welche Commits lokal, aber nicht auf dem Server vorhanden sind. der `send-pack`-Prozess schickt diese Information für jede Referenz, auf die sich der `push`-Befehl bezieht, an den `receive-pack` Prozess. Wenn Du beispielsweise den Branch `master` aktualisierst und einen Branch `experiment` hinzufügst, dann könnte die Antwort auf `send-pack` so aussehen: 0085ca82a6dff817ec66f44342007202690a93763949 15027957951b64cf874c3557a0f3547bd83b3ff6 refs/heads/master report-status 00670000000000000000000000000000000000000000 cdfdb42577e2506715f8cfeacdbabc092bf63e8d refs/heads/experiment @@ -1008,40 +1008,40 @@ Nachdem Dein `send-pack` Prozess jetzt den Zustand des Servers kennt, kann er al -Der SHA-1 Wert, der nur aus Nullen besteht, heißt, dass dort zuvor nichts war: Du fügst die `experiment` Referenz ja neu hinzu. Würdest Du eine Referenz löschen, würdest Du das Gegenteil sehen: nur Nullen auf der rechten Seite (xxx hu? wo ist die rechte seite? xxx) +Der SHA-1-Wert, der nur aus Nullen besteht, heißt, dass dort zuvor nichts war: Du fügst die `experiment`-Referenz ja neu hinzu. Würdest Du eine Referenz löschen, würdest Du das Gegenteil sehen: nur Nullen auf der rechten Seite. -Pro Referenz, die Du aktualisierst, schickt Git eine Zeile mit dem alten SHA, dem neuen SHA und der jeweiligen Referenz, die aktualisiert wird. Die erste Zeile listet zudem die Server Features. Als nächstes lädt der Client ein Packfile aller Objekte hoch, die der Server noch nicht kennt. Abschließend antwortet der Server mit einer Erfolgs- oder Fehlermeldung: +Pro Referenz, die Du aktualisierst, schickt Git eine Zeile mit dem alten SHA, dem neuen SHA und der jeweiligen Referenz, die aktualisiert wird. Die erste Zeile listet zudem die Server-Features auf. Als nächstes lädt der Client ein Packfile aller Objekte hoch, die der Server noch nicht kennt. Abschließend antwortet der Server mit einer Erfolgs- oder Fehlermeldung: 000Aunpack ok -#### Downloading Data #### +#### Daten herunterladen #### -Wenn Du Daten herunterlädst, sind daran die `fetch-pack` und `upload-pack` Prozesse beteiligt. Der Client startet einen `fetch-pack` Prozess, der sich mit einem `upload-pack` Prozess auf dem Server verbindet, um auszuhandeln, welche Daten heruntergeladen werden sollen. +Wenn Du Daten herunterlädst, sind daran die Prozesse `fetch-pack` und `upload-pack` beteiligt. Der Client startet einen `fetch-pack`-Prozess, der sich mit einem `upload-pack`-Prozess auf dem Server verbindet, um auszuhandeln, welche Daten heruntergeladen werden sollen. -Es gibt verschiedene Möglichkeiten, den `upload-pack` Prozess auf dem Server zu starten: einerseits via SSH auf die gleiche Weise wie den `receive-pack` Prozess. Und adnererseits über den Git Daemon, der standardmäßig auf dem Server auf dem Port 9418 läuft. Der `fetch-pack` Prozess schickt etwa folgendes an den Daemon: +Es gibt verschiedene Möglichkeiten, den `upload-pack`-Prozess auf dem Server zu starten: einerseits via SSH auf die gleiche Weise wie den `receive-pack`-Prozess. Und andererseits über den Git-Daemon, der standardmäßig auf dem Server auf dem Port 9418 läuft. Der `fetch-pack`-Prozess schickt etwa Folgendes an den Daemon: 003fgit-upload-pack schacon/simplegit-progit.git\0host=myserver.com\0 -Diese Zeile beginnt wiederum mit 4 Bytes, die angeben, wieviel Daten folgen. Dann kommt der auszuführende Befehl und ein Null Byte, und schließlich der Hostname des Servers und ein weiteres Null Byte. Der Git Daemon prüft, ob der Befehl ausgeführt werden kann, das Repository existiert und Schreibzugriff erlaubt. Wenn alles stimmt, startet er den `upload-pack` Prozess und gibt den Request dorthin weiter. +Diese Zeile beginnt wiederum mit 4 Bytes, die angeben, wieviel Daten folgen. Dann kommt der auszuführende Befehl und ein Null-Byte, und schließlich der Hostname des Servers und ein weiteres Null-Byte. Der Git-Daemon prüft, ob der Befehl ausgeführt werden kann, das Repository existiert und Schreibzugriff erlaubt. Wenn alles stimmt, startet er den `upload-pack`-Prozess und gibt den Request dorthin weiter. -Wenn Du den `fetch` Befehl über SSH verwendest, führt `fetch-pack` statt dessen etwas aus wie: +Wenn Du den `fetch`-Befehl über SSH verwendest, führt `fetch-pack` stattdessen etwas aus wie: $ ssh -x git@github.com "git-upload-pack 'schacon/simplegit-progit.git'" -In beiden Fällen wird, nachdem `fetch-pack` verbunden ist, `upload-pack` eine Antwort wie die folgende zurück schicken: +In beiden Fällen wird, nachdem `fetch-pack` verbunden ist, `upload-pack` eine Antwort wie die folgende zurückschicken: 0088ca82a6dff817ec66f44342007202690a93763949 HEAD\0multi_ack thin-pack \ side-band side-band-64k ofs-delta shallow no-progress include-tag @@ -1051,11 +1051,11 @@ In beiden Fällen wird, nachdem `fetch-pack` verbunden ist, `upload-pack` eine A -Die Antwort ähnelt der, mit der `receive-pack` antwortet, aber die aufgelisteten Features sind andere. Zusätzlich wird die HEAD Referenz mitgeschickt, sodass der Client weiß, was er auschecken muss, falls es sich um einen Clone handelt. +Die Antwort ähnelt der, mit der `receive-pack` antwortet, aber die aufgelisteten Features sind andere. Zusätzlich wird die HEAD-Referenz mitgeschickt, sodass der Client weiß, was er auschecken muss, falls es sich um einen Clone handelt. -Der `fetch-pack` Prozess inspiziert jetzt die vorhandenen Objekte und antwortet mit einer Liste von Objekten, wobei er das Schlüsselwort „want“ für Objekte verwendet, die benötigt werden, und „have“ für Objekte, die bereits vorhanden sind. Am Ende der Liste folgt das Schlüsselwort „done“. Der `upload-pack` Prozess schickt dann ein Packfile mit allen benötigten Objekten: +Der `fetch-pack`-Prozess inspiziert jetzt die vorhandenen Objekte und antwortet mit einer Liste von Objekten, wobei er das Schlüsselwort „want“ für Objekte verwendet, die benötigt werden, und „have“ für Objekte, die bereits vorhanden sind. Am Ende der Liste folgt das Schlüsselwort „done“. Der `upload-pack`-Prozess schickt dann ein Packfile mit allen benötigten Objekten: 0054want ca82a6dff817ec66f44342007202690a93763949 ofs-delta 0032have 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 @@ -1064,14 +1064,14 @@ Der `fetch-pack` Prozess inspiziert jetzt die vorhandenen Objekte und antwortet -Das ist ein sehr einfaches Beispiel. In komplexeren Fällen unterstützt der Client die `multi_ack` oder `side-band` Features. Aber obiges Beispiel verdeutlicht den grundlegenden Request-Response Zyklus der Smart Protokoll Prozesse. +Das ist ein sehr einfaches Beispiel. In komplexeren Fällen unterstützt der Client die Features `multi_ack` oder `side-band`. Aber obiges Beispiel verdeutlicht den grundlegenden Request-Response Zyklus der Prozesse bei schlauen Protokollen. ## Wartung und Datenwiederherstellung ## -Gelegentlich will man ein bisschen aufräumen – ein Repository verdichten, ein importiertes Repository entfernen (xxx) oder verloren gegangene Daten wieder herstellen. Dieses Kapitel wird sich mit einigen derartigen Szenarien befassen. +Gelegentlich will man ein bisschen aufräumen – ein Repository komprimieren, ein importiertes Repository aufräumen oder verloren gegangene Daten wiederherstellen. Dieses Kapitel wird sich mit einigen derartigen Szenarien befassen. ### Wartung ### @@ -1088,7 +1088,7 @@ Du kannst `auto gc` wie folgt manuell ausführen: -Wie schon erwähnt tut dies normalerweise gar nichts. Es müssen sich etwa 7.000 lose Objekte oder mehr als 50 Packfiles angesammelt haben, bevor Git tatsächlich die Garbage Collection startet. Du kannst diese Werte mit Hilfe der `gc.auto` bzw. `gc.autopacklimit` Konfigurationsvariablen manuell setzen. +Wie schon erwähnt tut dies normalerweise gar nichts. Es müssen sich etwa 7.000 lose Objekte oder mehr als 50 Packfiles angesammelt haben, bevor Git tatsächlich den echten gc-Befehl startet. Du kannst diese Werte mit Hilfe der Konfigurationsvariablen `gc.auto` bzw. `gc.autopacklimit` manuell setzen. @@ -1102,7 +1102,7 @@ Wie schon erwähnt tut dies normalerweise gar nichts. Es müssen sich etwa 7.000 -Nachdem Du `git gc` ausgeführt hast, werden diese Dateien um der Effizienz willen aus dem `refs` Verzeichnis entfernt und in eine Datei `.git/packed-refs` verschoben, die dann wie folgt aussieht: +Nachdem Du `git gc` ausgeführt hast, werden diese Dateien um der Effizienz willen aus dem Verzeichnis `refs` entfernt und in eine Datei `.git/packed-refs` verschoben, die dann wie folgt aussieht: $ cat .git/packed-refs # pack-refs with: peeled @@ -1114,22 +1114,22 @@ Nachdem Du `git gc` ausgeführt hast, werden diese Dateien um der Effizienz will -Wenn Du eine Referenz bearbeitest, lässt Git diese Datei unverändert und schreibt statt dessen eine neue Datei nach `refs/heads`. Um einen SHA für eine Referenz nachzuschlagen, schaut Git zunächst im `refs` Verzeichnis und danach erst in der `packed-refs` Datei nach, falls nötig. Wenn eine Referenz also nicht im `refs` Verzeichnis liegt, befindet sie sich wahrscheinlich in `packed-refs` Datei. +Wenn Du eine Referenz bearbeitest, lässt Git diese Datei unverändert und schreibt stattdessen eine neue Datei nach `refs/heads`. Um eine SHA-Prüfsumme für eine Referenz nachzuschlagen, schaut Git zunächst im Verzeichnis `refs` und danach erst in der Datei `packed-refs` nach, falls nötig. Wenn eine Referenz also nicht im Verzeichnis `refs` liegt, befindet sie sich wahrscheinlich in der Datei `packed-refs`. Beachte, dass die letzte Zeile der Datei mit `^` anfängt. Das bedeutet, dass der Tag darüber ein annotierter Tag ist und diese Zeile zeigt den Commit, auf den der annotierte Tag zeigt. -### Daten Wiederherstellung ### +### Daten-Wiederherstellung ### -Irgendwann wird es vielleicht mal vorkommen, dass Du während der Arbeit mit Git einen Commit verlierst. Normalerweise passiert das, wenn Du versehentlich einen Branch löschst, an dem Du gearbeitet hattest und den Du noch brauchst. Oder Du führst `git reset --hard` aus und stellst fest, dass Du einige der Commits noch brauchst. Nehmen wir an, Du steckst in einer solchen Situation – wie kannst Du Deine Commits wieder herstellen? +Irgendwann wird es vielleicht mal vorkommen, dass Du während der Arbeit mit Git einen Commit verlierst. Normalerweise passiert das, wenn Du versehentlich einen Branch löschst, an dem Du gearbeitet hattest und den Du noch brauchst. Oder Du führst `git reset --hard` aus und stellst fest, dass Du einige der Commits noch brauchst. Nehmen wir an, Du steckst in einer solchen Situation – wie kannst Du Deine Commits dann wiederherstellen? -Das folgende Beispiel setzt zuerst den `master` Branch auf einen älteren Commit zurück und stellt die verlorenen Commits dann wieder her. Zunächst schauen wir uns den gegenwärtigen Zustand des Repositories an: +Das folgende Beispiel setzt zuerst den Branch `master` auf einen älteren Commit zurück und stellt die verlorenen Commits dann wieder her. Zunächst schauen wir uns den gegenwärtigen Zustand des Repositorys an: $ git log --pretty=oneline ab1afef80fac8e34258ff41fc1b867c702daa24b modified repo a bit @@ -1140,7 +1140,7 @@ Das folgende Beispiel setzt zuerst den `master` Branch auf einen älteren Commit -Jetzt setzen wir den `master` Branch zurück auf den mittleren Commit. +Jetzt setzen wir den Branch `master` auf den mittleren Commit zurück: $ git reset --hard 1a410efbd13591db07496601ebc7a059dd55cfe9 HEAD is now at 1a410ef third commit @@ -1151,11 +1151,11 @@ Jetzt setzen wir den `master` Branch zurück auf den mittleren Commit. -Du hast damit die oberen beiden Commits verloren, d.h. es gibt keinen Branch mehr, von dem aus diese Commits erreichbar wären. Um sie wieder herzustellen kannst Du einen neuen Branch anlegen, der auf den SHA Hash des obersten (letzten) Commits zeigt. Der Trick besteht darin, diesen letzten Commit Hash heraus zu finden. Es ist ja nicht so, dass Du Dir jederzeit all die Hashes merken könntest, oder? +Du hast damit die oberen beiden Commits verloren, d.h. es gibt keinen Branch mehr, von dem aus diese Commits erreichbar wären. Um sie wiederherzustellen, kannst Du einen neuen Branch anlegen, der auf den SHA-Hash des obersten (letzten) Commits zeigt. Der Trick besteht darin, diesen letzten Commit-Hash herauszufinden. Es ist ja nicht so, dass Du Dir jederzeit all die Hashes merken könntest, oder? -In der Regel ist der schnellste Weg, solche Hashes zu finden, der Befehl `git reflog`. Während Du mit Git arbeitest, macht Git im Stillen fortlaufende Notizen darüber, was HEAD ist. Jedes Mal, wenn Du einen Commit anlegst oder den Branch wechselst, wird das „Reflog“ aktualisiert. Das Reflog wird außerdem vom Befehl `git update-ref` verwendet – ein weiterer guter Grund, nicht statt dessen einfach den SHA Wert in eine Referenz Datei zu schreiben (wie wir das in der Sektion „Git Referenzen“ zuvor in diesem Kapitel besprochen haben). Du kannst also jederzeit nachschlagen, woran Du jeweils gearbeitet hast, indem Du den Befehl `git reflog` verwendest: +In der Regel ist der schnellste Weg, solche Hashes zu finden, der Befehl `git reflog`. Während Du mit Git arbeitest, macht Git im Stillen fortlaufende Notizen darüber, was HEAD ist. Jedes Mal, wenn Du einen Commit anlegst oder den Branch wechselst, wird das „Reflog“ aktualisiert. Das Reflog wird außerdem vom Befehl `git update-ref` verwendet – ein weiterer guter Grund, nicht stattdessen einfach den SHA-Wert in eine Referenz-Datei zu schreiben (wie wir das in der Sektion „Git-Referenzen“ zuvor in diesem Kapitel besprochen haben). Du kannst also jederzeit nachschlagen, woran Du jeweils gearbeitet hast, indem Du den Befehl `git reflog` verwendest: $ git reflog 1a410ef HEAD@{0}: 1a410efbd13591db07496601ebc7a059dd55cfe9: updating HEAD @@ -1163,7 +1163,7 @@ In der Regel ist der schnellste Weg, solche Hashes zu finden, der Befehl `git re -Das zeigt also die beiden verloren gegangenen Commits an, die wir zuvor ausgecheckt hatten. Allerdings zeigt es auch nicht viel mehr Information. Um das Reflog in einer anderen, etwas nützlicheren Weise anzuzeigen, kannst Du `git log -g` verwenden. Das gibt das Reflog im gewohnten Log Format aus: +Das zeigt also die beiden verloren gegangenen Commits an, die wir zuvor ausgecheckt hatten. Allerdings zeigt es auch nicht viel mehr Information. Um das Reflog in einer anderen, etwas nützlicheren Weise anzuzeigen, kannst Du `git log -g` verwenden. Das gibt das Reflog im gewohnten Log-Format aus: $ git log -g commit 1a410efbd13591db07496601ebc7a059dd55cfe9 @@ -1184,7 +1184,7 @@ Das zeigt also die beiden verloren gegangenen Commits an, die wir zuvor ausgeche -Es sieht also so aus, als sei der untere Commit derjenige, den Du verloren hast, aber noch brauchst. Du kannst ihn jetzt wieder herstellen, indem Du einen neuen Branch erstellst, der auf diesen Commit zeigt. Beispielsweise kannst Du einen Branch `recover-branch` anlegen, der auf den Commit `ab1afef` zeigt: +Es sieht also so aus, als sei der untere Commit derjenige, den Du verloren hast, aber noch brauchst. Du kannst ihn jetzt wiederherstellen, indem Du einen neuen Branch erstellst, der auf diesen Commit zeigt. Beispielsweise kannst Du einen Branch `recover-branch` anlegen, der auf den Commit `ab1afef` zeigt: $ git branch recover-branch ab1afef $ git log --pretty=oneline recover-branch @@ -1194,17 +1194,17 @@ Es sieht also so aus, als sei der untere Commit derjenige, den Du verloren hast, cac0cab538b970a37ea1e769cbbde608743bc96d second commit fdf4fc3344e67ab068f836878b6c4951e3b15f3d first commit - + + -Sehr gut. Du hast jetzt einen neuen Branch `recover-branch`, der diejenigen Commits enthält, die sich zuvor in Deinem `master` Branch befanden. Damit hast Du wieder Zugriff auf die beiden verloren gegangenen Commits. Als nächstes nehmen wir aber außerdem an, dass diese verlorenen Commits aus irgendeinem Grunde nicht im Reflog enthalten sind – Du kannst das z.B. simulieren, indem Du den Branch `recover-branch` und das Reflog löschst. Damit sind die beiden Commits jetzt von nirgendwo her mehr erreichbar: +Sehr gut. Du hast jetzt einen neuen Branch `recover-branch`, der diejenigen Commits enthält, die sich zuvor in Deinem Branch `master` befanden. Damit hast Du wieder Zugriff auf die beiden verloren gegangenen Commits. Als nächstes nehmen wir aber außerdem an, dass diese verlorenen Commits aus irgendeinem Grunde nicht im Reflog enthalten sind – Du kannst das z.B. simulieren, indem Du den Branch `recover-branch` und das Reflog löschst. Damit sind die beiden Commits jetzt von nirgendwo her mehr erreichbar: $ git branch -D recover-branch $ rm -Rf .git/logs/ -Das Reflog wird im Verzeichnis `.git/logs/` aufbewahrt, d.h. Du hast nun faktisch kein Reflog mehr. Wie kann man einen Commit jetzt noch wieder herstellen? Eine Möglichkeit dazu ist der Befehl `git fsck`, der die Git Datenbank Integrität prüft. Wenn Du den Befehl mit der Option `--full` ausführst, zeigt er alle Objekte an, auf die nicht von einem anderen Objekt verwiesen wird: +Das Reflog wird im Verzeichnis `.git/logs/` aufbewahrt, d.h. Du hast nun faktisch kein Reflog mehr. Wie kann man einen Commit jetzt noch wiederherstellen? Eine Möglichkeit dazu ist der Befehl `git fsck`, der die Integrität der Git-Datenbank prüft. Wenn Du den Befehl mit der Option `--full` ausführst, zeigt er alle Objekte an, auf die nicht von einem anderen Objekt verwiesen wird: $ git fsck --full dangling blob d670460b4b4aece5915caf5c68d12f560a9fe3e4 @@ -1214,26 +1214,26 @@ Das Reflog wird im Verzeichnis `.git/logs/` aufbewahrt, d.h. Du hast nun faktisc -In diesem Fall findest Du den verlorenen Commit nach dem (xxx dangling xxx) Commit. Du kannst ihn dann auf die selbe Weise wieder herstellen wie zuvor, indem Du einen Branch erstellst, der auf diesen Commit Hash zeigt. +In diesem Fall findest Du den verlorenen Commit nach den Worten „dangling commit“. Du kannst ihn dann auf dieselbe Weise wiederherstellen wie zuvor, indem Du einen Branch erstellst, der auf diesen Commit-Hash zeigt. ### Objekte entfernen ### -Git ist in vielerlei Hinsicht unschlagbar, aber es gibt auch Features, die Probleme verursachen können. Ein solches Problem kann darin bestehen, dass `git clone` die vollständige Historie eines Projektes herunter lädt, d.h. jede einzelne Version jeder einzelnen Datei. Das ist eine feine Sache, solange es sich um Quellcode handelt, den Git ist darauf optimiert, diese Art von Daten effizient zu komprimieren. Wenn allerdings irgendwann einmal eine einzelne, sehr große Datei zur Versionskontrolle hinzugefügt wurde, wird jeder Clone dieses Repositories diese Datei gezwungenermaßen herunter laden müssen – auch dann, wenn die Datei inzwischen aus dem Repository entfernt würde. Weil sie über die Historie erreichbar ist, muss die Datei vorhanden sein. +Git ist in vielerlei Hinsicht unschlagbar, aber es gibt auch Features, die Probleme verursachen können. Ein solches Problem kann darin bestehen, dass `git clone` die vollständige Historie eines Projektes herunterlädt, d.h. jede einzelne Version jeder einzelnen Datei. Das ist eine feine Sache, solange es sich um Quellcode handelt, denn Git ist darauf optimiert, diese Art von Daten effizient zu komprimieren. Wenn allerdings irgendwann einmal eine einzelne, sehr große Datei zur Versionskontrolle hinzugefügt wurde, wird jeder Clone dieses Repositorys diese Datei gezwungenermaßen herunterladen müssen – auch dann, wenn die Datei inzwischen aus dem Repository entfernt würde. Weil sie über die Historie erreichbar ist, muss die Datei vorhanden sein. -Hierin kann ein großes Problem bestehen, wenn Du Subversion oder Perforce Repositories nach Git konvertierst. Weil Du in diesen Systemen nicht die gesamte Historie herunter lädst, kann diese Art von (xxx addition??? hu? xxx) einige unangenehme Konsequenzen haben. Wenn Du Dein Repository aus einem anderen System importiert hast oder aus irgendeinem anderen Grunde findest, dass es sehr viel größer ist als es eigentlich sein sollte, kannst Du große Objekte wie folgt suchen und entfernen. +Hierin kann ein großes Problem bestehen, wenn Du Subversion- oder Perforce-Repositorys nach Git konvertierst. Weil Du in diesen Systemen nicht die gesamte Historie herunterlädst, kann diese Art von Hinzufügung einige unangenehme Konsequenzen haben. Wenn Du Dein Repository aus einem anderen System importiert hast oder aus irgendeinem anderen Grunde findest, dass es sehr viel größer ist, als es eigentlich sein sollte, kannst Du große Objekte wie folgt suchen und entfernen. -Sei Dir allerdings bewusst, dass diese Technik die Commit Historie zerstört. Sie schreibt angefangen beim ursprünglichen Tree jedes einzelne Commit Objekt neu, um die jeweilige, große Datei zu entfernen. Wenn Du das direkt nach einem Import tust, d.h. bevor jemand angefangen hat, auf der Basis eines Commits zu arbeiten, ist das in Ordnung – andernfalls müssen alle Mitarbeiter ihre Arbeit auf Deinen Commit rebasen. +Sei Dir allerdings bewusst, dass diese Technik die Commit-Historie zerstört. Sie schreibt angefangen beim ursprünglichen Tree jedes einzelne Commit-Objekt neu, um die jeweilige, große Datei zu entfernen. Wenn Du das direkt nach einem Import tust, d.h. bevor jemand angefangen hat, auf der Basis eines Commits zu arbeiten, ist das in Ordnung – andernfalls müssen alle Mitarbeiter ihre Arbeit auf Deinen Commit rebasen. -Um das zu demonstrieren, werden wir eine große Datei zu Deinem Test Repository hinzufügen, sie dann im nächsten Commit löschen, in der Datenbank nachschlagen und sie schließlich dauerhaft aus dem Repository entfernen. Als erstes committe also eine große Datei in Dein Repository: +Um das zu demonstrieren, werden wir eine große Datei zu Deinem Test-Repository hinzufügen, sie dann im nächsten Commit löschen, in der Datenbank nachschlagen und sie schließlich dauerhaft aus dem Repository entfernen. Als erstes checke also eine große Datei in Dein Repository ein: $ curl http://kernel.org/pub/software/scm/git/git-1.6.3.1.tar.bz2 > git.tbz2 $ git add git.tbz2 @@ -1255,7 +1255,7 @@ Oha. Du wolltest keinen dermaßen großen Tarball in Deinem Projekt. Am besten l -Jetzt lassen wir die Garbage Collection über die Datenbank laufen und sehen, wieviel Platz sie braucht: +Jetzt lassen wir die Garbage-Collection über die Datenbank laufen und sehen, wieviel Platz sie braucht: $ git gc Counting objects: 21, done. @@ -1266,7 +1266,7 @@ Jetzt lassen wir die Garbage Collection über die Datenbank laufen und sehen, wi -Du kannst auch den `count-objects` Befehl laufen lassen, um einen schnellen Überblick darüber zu erhalten, wieviel Platz das Repository einnimmt: +Du kannst auch den Befehl `count-objects` laufen lassen, um einen schnellen Überblick darüber zu erhalten, wieviel Platz das Repository einnimmt: $ git count-objects -v count: 4 @@ -1279,11 +1279,11 @@ Du kannst auch den `count-objects` Befehl laufen lassen, um einen schnellen Übe -Der `size-pack` Eintrag zeigt die Größe der Packfiles in Kilobytes, d.h. Dein Repository braucht 2 MB. Vor dem letzten Commit lag dieser Wert eher bei 2 KB. D.h., die Datei wurde im letzten Commit eindeutig nicht aus der History entfernt. Jedes Mal, wenn jemand künftig dieses sehr kleine Repository clont, wird er die 2 MB mit herunterladen müssen – nur weil wir versehentlich diese große Datei hinzugefügt hatten. Also versuchen wir, sie endgültig los zu werden. +Der `size-pack`-Eintrag zeigt die Größe der Packfiles in Kilobytes an, d.h. Dein Repository braucht 2 MB. Vor dem letzten Commit lag dieser Wert eher bei 2 KB. D.h., die Datei wurde im letzten Commit eindeutig nicht aus der History entfernt. Jedes Mal, wenn jemand künftig dieses sehr kleine Repository klont, wird er die 2 MB mit herunterladen müssen – nur weil wir versehentlich diese große Datei hinzugefügt hatten. Also versuchen wir, sie endgültig loszuwerden. -Zunächst mal müssen wir sie finden. In diesem Fall wissen wir bereits, um welche Datei es sich handelt. Aber nehmen wir an, wir wüssten es nicht. Wie würdest Du herausfinden, welche Datei (oder welche Dateien) so viel Platz verbrauchen? Wenn Du `git gc` laufen gelassen hast, werden sich alle Objekte in einem Packfile befinden. Du kannst dann große Objekte identifizieren, indem Du einen weiteren Plumbing Befehl, nämlich `git verify-pack` ausführst und nach dem dritten Feld der Ausgabe sortierst, d.h. der Dateigröße. Du kannst sie außerdem durch den `tail` Befehl leiten, denn Du bist ja nur an den wenigen größten Objekten interessiert: +Zunächst mal müssen wir sie finden. In diesem Fall wissen wir bereits, um welche Datei es sich handelt. Aber nehmen wir an, wir wüssten es nicht. Wie würdest Du herausfinden, welche Datei (oder welche Dateien) so viel Platz verbrauchen? Wenn Du `git gc` laufen gelassen hast, werden sich alle Objekte in einem Packfile befinden. Du kannst dann große Objekte identifizieren, indem Du einen weiteren Plumbing-Befehl, nämlich `git verify-pack` ausführst und nach dem dritten Feld der Ausgabe sortierst, d.h. der Dateigröße. Du kannst sie außerdem durch den `tail` Befehl leiten, denn Du bist ja nur an den wenigen größten Objekten interessiert: $ git verify-pack -v .git/objects/pack/pack-3f8c0...bb.idx | sort -k 3 -n | tail -3 e3f094f522629ae358806b17daf78246c27c007b blob 1486 734 4667 @@ -1292,14 +1292,14 @@ Zunächst mal müssen wir sie finden. In diesem Fall wissen wir bereits, um welc -Das größte Objekt ist ganz klar das letzte: es ist 2 MB groß. Um herauszufinden, welche Datei das ist, kannst Du den `rev-list` Befehl verwenden, den wir in Kapitel 7 schon einmal kurz verwendet haben. Wenn Du die Optionen `--objects` und `rev-list` verwendest, werden alle Commit und Blob SHAs mit den jeweiligen Dateipfaden aufgelistet, die mit ihnen assoziiert sind. Auf diese Weise kannst Du den Namen des Blobs finden: +Das größte Objekt ist ganz klar das letzte: es ist 2 MB groß. Um herauszufinden, welche Datei das ist, kannst Du den `rev-list` Befehl verwenden, den wir in Kapitel 7 schon einmal kurz verwendet haben. Wenn Du die Optionen `--objects` und `rev-list` verwendest, werden alle Commit- und Blob-SHAs mit den jeweiligen Dateipfaden aufgelistet, die mit ihnen assoziiert sind. Auf diese Weise kannst Du den Namen des Blobs finden: $ git rev-list --objects --all | grep 7a9eb2fb 7a9eb2fba2b1811321254ac360970fc169ba2330 git.tbz2 -Du musst diese Datei jetzt aus allen Trees entfernen, in denen er sich befindet. Du kannst leicht herausfinden, welche Commits diese Datei verändert haben: +Du musst diese Datei jetzt aus allen Trees entfernen, in denen sie sich befindet. Du kannst leicht herausfinden, welche Commits diese Datei verändert haben: $ git log --pretty=oneline --branches -- git.tbz2 da3f30d019005479c99eb4c3406225613985a1db oops - removed large tarball @@ -1307,7 +1307,7 @@ Du musst diese Datei jetzt aus allen Trees entfernen, in denen er sich befindet. -Es geht also darum, alle Commits angefangen bei `6df76` neu zu schreiben, sodass der Tarball nicht mehr in Deiner Git Historie enthalten ist. Um das zu erreichen, verwendest Du den Befehl `git filter-branch`, den wir schon mal in Kapitel 6 verwendet haben: +Es geht also darum, alle Commits angefangen bei `6df76` neu zu schreiben, sodass der Tarball nicht mehr in Deiner Git-Historie enthalten ist. Um das zu erreichen, verwendest Du den Befehl `git filter-branch`, den wir schon mal in Kapitel 6 verwendet haben: $ git filter-branch --index-filter \ 'git rm --cached --ignore-unmatch git.tbz2' -- 6df7640^.. @@ -1317,7 +1317,7 @@ Es geht also darum, alle Commits angefangen bei `6df76` neu zu schreiben, sodass -Die `--index-filter` Option ist ähnlich der `--tree-filter` Option aus Kapitel 6. Allerdings übergibt man in diesem Fall nicht einen Befehl, der die Dateien verändert, die sich jeweils ausgecheckt auf der Festplatte befinden. Statt dessen verändert man jeweils die Staging Area bzw. den Index. Statt eine bestimmte Datei mit z.B: `rm file` zu entfernen, müssen wir also `git rm --cached` verwenden – denn wir wollen sie aus dem Index, nicht von der Festplatte löschen. Der Grund dafür ist einfach Geschwindigkeit: Git braucht nicht jede einzelne Revision auf die Festplatte auszuchecken, um den Filter anzuwenden. Auf diese Weise läuft der ganze Prozess sehr viel schneller. Man kann dieselbe Aufgabe aber auch mit `--tree-filter` erledigen, wenn man will. Die Option `--ignore-match` weist Git an, nicht mit einer Fehlermeldung abzubrechen, wenn die Datei, die wir löschen wollen, nicht vorhanden ist. Außerdem teilen wir `filter-branch` mit, die Historie nur von dem Commit `6df7640` an umzuschreiben. Andernfalls würde der Befehl von ganz vorn beginnen und unnötig länger brauchen. +Die Option `--index-filter` ist ähnlich der Option `--tree-filter` aus Kapitel 6. Allerdings übergibt man in diesem Fall nicht einen Befehl, der die Dateien verändert, die sich jeweils ausgecheckt auf der Festplatte befinden. Stattdessen verändert man jeweils die Staging-Area bzw. den Index. Statt eine bestimmte Datei mit z.B: `rm file` zu entfernen, müssen wir also `git rm --cached` verwenden – denn wir wollen sie aus dem Index, nicht von der Festplatte löschen. Der Grund dafür ist einfach Geschwindigkeit: Git braucht nicht jede einzelne Revision auf die Festplatte auszuchecken, um den Filter anzuwenden. Auf diese Weise läuft der ganze Prozess sehr viel schneller. Man kann dieselbe Aufgabe aber auch mit `--tree-filter` erledigen, wenn man will. Die Option `--ignore-match` weist Git an, nicht mit einer Fehlermeldung abzubrechen, wenn die Datei, die wir löschen wollen, nicht vorhanden ist. Außerdem teilen wir `filter-branch` mit, die Historie nur von dem Commit `6df7640` an umzuschreiben. Andernfalls würde der Befehl von ganz vorn beginnen und unnötig länger brauchen. @@ -1347,15 +1347,15 @@ Prüfen wir also, wieviel Platz wir damit eingespart haben: -Das gepackte Repository umfasst jetzt nur noch 7K – sehr viel besser als die vorherigen 2MB. Du kannst an dem Wert `size` erkennen, dass sich die große Datei selbst jetzt immer noch in Deinen loosen Objekten befindet. Aber sie wird bei einem `git push` oder anschließenden `git clone` nicht übermittelt werden – und das war unser Ziel. Wenn Du das wirklich willst, kannst Du sie jetzt vollständig und endgültig mit `git prune --expire` aus Deinem Repository löschen. +Das gepackte Repository umfasst jetzt nur noch 7K – sehr viel besser als die vorherigen 2MB. Du kannst an dem Wert `size` erkennen, dass sich die große Datei selbst jetzt immer noch in Deinen losen Objekten befindet. Aber sie wird bei einem `git push` oder anschließenden `git clone` nicht übermittelt werden – und das war unser Ziel. Wenn Du das wirklich willst, kannst Du sie jetzt vollständig und endgültig mit `git prune --expire` aus Deinem Repository löschen. ## Zusammenfassung ## -Du solltest jetzt ein gutes Verständnis davon haben, was Git im Hintergrund tut, und in einem gewissen Maße auch davon, wie es implementiert ist. In diesem Kapitel haben wir eine Reihe von Plumbing Befehlen besprochen, als Befehlen, die grundlegender und einfacher als die Porzellan Befehle sind, um die es im restlichen Buch ging. Dieses Verständnis sollte Dir helfen, zu verstehen, warum Git tut, was es tut – und natürlich auch dabei, Deine eigenen Werkzeuge und Hilfsskripte zu schreiben, um einen bestimmten Workflow für Dich anzupassen. +Du solltest jetzt ein gutes Verständnis davon haben, was Git im Hintergrund tut, und in einem gewissen Maße auch davon, wie es implementiert ist. In diesem Kapitel haben wir eine Reihe von Plumbing-Befehlen besprochen, also Befehlen, die grundlegender und einfacher als die Porcelain-Befehle sind, um die es im restlichen Buch ging. Dieses Verständnis sollte Dir helfen, zu verstehen, warum Git tut, was es tut – und natürlich auch dabei, Deine eigenen Werkzeuge und Hilfsskripte zu schreiben, um einen bestimmten Arbeitsablauf für Dich anzupassen. -Git als ein Dateisystem, das Inhalte addressieren kann, ist ein äußerst mächtiges Werkzeug, das Du leicht als mehr als „nur“ als (xxx) ein VCS einsetzen kannst. Ich hoffe, Du kannst Dein neugewonnenes Wissen der Git Interna nutzen, um Deine eigene tolle Anwendung dieser Technologie zu implementieren und Dich wohler damit zu fühlen, Git auch in fortgeschrittener Weise zu benutzen. +Git als ein Dateisystem, das Inhalte addressieren kann, ist ein äußerst mächtiges Werkzeug, das Du leicht für mehr als „nur“ als VCS einsetzen kannst. Ich hoffe, Du kannst Dein neugewonnenes Wissen der Git Interna nutzen, um Deine eigene tolle Anwendung dieser Technologie zu implementieren und Dich wohler damit zu fühlen, Git auch in fortgeschrittener Weise zu benutzen. diff --git a/de/README.md b/de/README.md index e5774f6d9..a8d214960 100644 --- a/de/README.md +++ b/de/README.md @@ -1,3 +1,5 @@ +[![Build-Status](https://secure.travis-ci.org/progit-de/progit.png?branch=master)](https://travis-ci.org/progit-de/progit) + # Deutsche Übersetzung # Die deutsche Übersetzung wird im Repository progit-de/progit verwaltet. Wenn Du an der deutschen Übersetzung mitarbeiten willst, dann melde Dich am besten bei uns. Du kannst dazu einen Issue im Repository progit-de/progit erzeugen. Wir werden Dir dann einen Vorschlag machen, wie Du uns am besten helfen kannst. Der Workflow an sich ist unter Workflow beschrieben. Ein Status der Übersetzung der jeweiligen Kapitel findest Du unter "Status der Übersetzung". @@ -13,26 +15,26 @@ In diesem Projekt kannst Du Dich nun austoben und Deinen Beitrag zur Übersetzun Beispielhaftes Vorgehen: git clone git@github.com:deinname/progit.git - + # Trage das deutsche Repository ebenso als Remote ein git remote add progit-de git@github.com:progit-de/progit.git - + # Lokalen Branch anlegen und daran arbeiten git checkout -b Chapter71 git commit -m "[de] Fix headings in chapter 7.1" - + # Wenn Deine Arbeit in sich abgeschlossen ist, kannst Du die Ergebnisse pushen. # Vor einem Push solltest Du allerdings prüfen, ob sich zwischenzeitlich # das Repository git@github.com:progit-de/progit.git aktualisiert hat. git fetch progit-de - - # Falls es sich aktualisiert hat, führe einen Rebase aus und + + # Falls es sich aktualisiert hat, führe einen Rebase aus und # behebe die ggf. aufgetretenden Konflikte git rebase progit-de/next - + # Pushe Deine Ergebnisse in Dein Github Repository git push origin - + Informiere uns jetzt mit einem Pull Request unter Github, dass Dein Branch fertiggestellt und bereit zum mergen ist. Wir werden dann Dein Ergebnis prüfen bzw. ein weiterer Helfer wird Dein Ergebnis reviewen. Das kann dazu führen, dass Du Deine Übersetzung noch überarbeiten musst. Siehe das Review als positive Hilfestellung damit das Ergebnis insgesamt besser wird und nimm die Kritik nicht negativ auf. Danach werden wir Deine Arbeit übernehmen und schließlich in den Hauptzweig unter progit/progit einpflegen. @@ -44,7 +46,7 @@ Die Commit Nachrichten beginnen mit einem vorangestellten [de], dann ein Leerzei Beispiel: [de] Remove comment for Figure 7-1 because it is shown on git-scm.com - + - Bla bla blub ## Vorgaben für das Übersetzen ## @@ -63,6 +65,50 @@ Beispiel: * Bei englischen Nomen, die auf "y" enden, wird beim Plural nur ein einzelnes "s" angehängt (kein ies). Siehe hierzu auch http://www.duden.de/sprachwissen/sprachratgeber/crashkurs--in-25-schritten-zur-neuen-rechtschreibung +#### Schreibweise von verschiedenen Git-Begriffen #### + +##### A - D ##### + +* Branch (Plural: Branches) +* Branch-Name +* Branch-Referenz (Plural: Branch-Referenzen) +* Commit +* Commit-Datum +* Commit-ID +* Commit-Objekt (Plural: Commit-Objekte) +* Commit-Nachricht +* Drei-Punkte-Syntax + +##### E - H ##### + +* Git-Repository +* HEAD +* HEAD-Referenz + +##### I - Q ##### + +* der Klon (Plural: Klone) +* Low-Level-Operation + +##### R - T ##### + +* Reflog-Ausgabe +* Remote-Repository +* Repository (Plural: Repositorys) +* SHA-1 +* SHA-1-Hash (Genitiv: SHA-1-Hashes) +* SHA-1-Hashwert (Plural: SHA-1-Hashwerte) +* SHA-1-Prüfsumme +* SHA-1-Wert +* stagen (gestaget, ungestaget) +* Staging-Area +* Stash +* stashen + +##### U - Z ##### + +* Zwei-Punkte-Syntax + ### Übersetzung von Git spezifischen Begriffen ### Wir versuchen die englischen Fachbegriffe, die in der Welt von Git existieren, zu benutzen. Zusätzlich versuchen wir aber immer, dass ein neu eingeführter Git-spezifischer Begriff, auch auf Deutsch erklärt wird. @@ -379,63 +425,63 @@ Bitte den Status nicht aktualisieren. Dies übernimmt ein Maintainer. Ja Nein Ja -Review notwendig +Ok 6.1 Ja Nein Ja -Review notwendig +Ok 6.2 Ja Nein Ja -Review notwendig +Ok 6.3 Ja Nein Ja -Review notwendig +Ok 6.4 Ja Nein Ja -Review notwendig +Ok 6.5 Ja Nein Ja -Review notwendig +Ok 6.6 -Nein +Ja Nein Ja -Übersetzung fehlt +Ok 6.7 Nein Nein Ja -Übersetzung fehlt +Ok 6.8 Nein Nein Ja -Übersetzung fehlt +Ok 7 @@ -512,63 +558,63 @@ Bitte den Status nicht aktualisieren. Dies übernimmt ein Maintainer. Ja Nein Ja -Review notwendig +Ok 9.1 Ja Nein Ja -Review notwendig +Ok 9.2 Ja Nein Ja -Review notwendig +Ok 9.3 Ja Nein Ja -Review notwendig +Ok 9.4 Teilweise Nein Ja -Review notwendig +Ok 9.5 Ja Nein Ja -Review notwendig +Ok 9.6 Ja Nein Ja -Review notwendig +Ok 9.7 Ja Nein Ja -Review notwendig +Ok 9.8 Ja Nein Ja -Review notwendig +Ok Index of Commands diff --git a/en/01-introduction/01-chapter1.markdown b/en/01-introduction/01-chapter1.markdown index c7f12a2ed..62f97d3b9 100644 --- a/en/01-introduction/01-chapter1.markdown +++ b/en/01-introduction/01-chapter1.markdown @@ -1,6 +1,6 @@ # Getting Started # -This chapter will be about getting started with Git. We will begin at the beginning by explaining some background on version control tools, then move on to how to get Git running on your system and finally how to get it setup to start working with. At the end of this chapter you should understand why Git is around, why you should use it and you should be all setup to do so. +This chapter will be about getting started with Git. We will begin by explaining some background on version control tools, then move on to how to get Git running on your system and finally how to get it set up to start working with. At the end of this chapter you should understand why Git is around, why you should use it and you should be all set up to do so. ## About Version Control ## @@ -102,7 +102,7 @@ Now, pay attention. This is the main thing to remember about Git if you want the This leads us to the three main sections of a Git project: the Git directory, the working directory, and the staging area. Insert 18333fig0106.png -Figure 1-6. Working directory, staging area, and git directory. +Figure 1-6. Working directory, staging area, and Git directory. The Git directory is where Git stores the metadata and object database for your project. This is the most important part of Git, and it is what is copied when you clone a repository from another computer. @@ -116,7 +116,7 @@ The basic Git workflow goes something like this: 2. You stage the files, adding snapshots of them to your staging area. 3. You do a commit, which takes the files as they are in the staging area and stores that snapshot permanently to your Git directory. -If a particular version of a file is in the git directory, it’s considered committed. If it’s modified but has been added to the staging area, it is staged. And if it was changed since it was checked out but has not been staged, it is modified. In Chapter 2, you’ll learn more about these states and how you can either take advantage of them or skip the staged part entirely. +If a particular version of a file is in the Git directory, it’s considered committed. If it’s modified but has been added to the staging area, it is staged. And if it was changed since it was checked out but has not been staged, it is modified. In Chapter 2, you’ll learn more about these states and how you can either take advantage of them or skip the staged part entirely. ## Installing Git ## @@ -129,7 +129,7 @@ If you can, it’s generally useful to install Git from source, because you’ll To install Git, you need to have the following libraries that Git depends on: curl, zlib, openssl, expat, and libiconv. For example, if you’re on a system that has yum (such as Fedora) or apt-get (such as a Debian based system), you can use one of these commands to install all of the dependencies: $ yum install curl-devel expat-devel gettext-devel \ - openssl-devel zlib-devel + openssl-devel zlib-devel perl-devel asciidoc xmlto $ apt-get install libcurl4-gnutls-dev libexpat1-dev gettext \ libz-dev libssl-dev @@ -153,7 +153,7 @@ After this is done, you can also get Git via Git itself for updates: If you want to install Git on Linux via a binary installer, you can generally do so through the basic package-management tool that comes with your distribution. If you’re on Fedora, you can use yum: - $ yum install git-core + $ yum install git Or if you’re on a Debian-based distribution like Ubuntu, try apt-get: @@ -161,38 +161,42 @@ Or if you’re on a Debian-based distribution like Ubuntu, try apt-get: ### Installing on Mac ### -There are two easy ways to install Git on a Mac. The easiest is to use the graphical Git installer, which you can download from the Google Code page (see Figure 1-7): +There are three easy ways to install Git on a Mac. The easiest is to use the graphical Git installer, which you can download from the SourceForge page (see Figure 1-7): - http://code.google.com/p/git-osx-installer + http://sourceforge.net/projects/git-osx-installer/ Insert 18333fig0107.png Figure 1-7. Git OS X installer. The other major way is to install Git via MacPorts (`http://www.macports.org`). If you have MacPorts installed, install Git via - $ sudo port install git-core +svn +doc +bash_completion +gitweb + $ sudo port install git +svn +doc +bash_completion +gitweb You don’t have to add all the extras, but you’ll probably want to include +svn in case you ever have to use Git with Subversion repositories (see Chapter 8). +Homebrew (`http://brew.sh/`) is another alternative to install Git. If you have Homebrew installed, install Git via + + $ brew install git + ### Installing on Windows ### Installing Git on Windows is very easy. The msysGit project has one of the easier installation procedures. Simply download the installer exe file from the GitHub page, and run it: - http://msysgit.github.com/ + http://msysgit.github.io After it’s installed, you have both a command-line version (including an SSH client that will come in handy later) and the standard GUI. -Note on Windows usage: you should use Git with the provided msysGit shell (Unix style), it allows to use the complex lines of command given in this book. If you need, for some reason, to use the native Windows shell / command line console, you have to use double quotes instead of simple quotes (for parameters with spaces in them) and you must quote the parameters ending with the circumflex accent (^) if they are last on the line, as it is a continuation symbol in Windows. +Note on Windows usage: you should use Git with the provided msysGit shell (Unix style), it allows to use the complex lines of command given in this book. If you need, for some reason, to use the native Windows shell / command line console, you have to use double quotes instead of single quotes (for parameters with spaces in them) and you must quote the parameters ending with the circumflex accent (^) if they are last on the line, as it is a continuation symbol in Windows. ## First-Time Git Setup ## Now that you have Git on your system, you’ll want to do a few things to customize your Git environment. You should have to do these things only once; they’ll stick around between upgrades. You can also change them at any time by running through the commands again. -Git comes with a tool called git config that lets you get and set configuration variables that control all aspects of how Git looks and operates. These variables can be stored in three different places: +Git comes with a tool called `git config` that lets you get and set configuration variables that control all aspects of how Git looks and operates. These variables can be stored in three different places: * `/etc/gitconfig` file: Contains values for every user on the system and all their repositories. If you pass the option` --system` to `git config`, it reads and writes from this file specifically. * `~/.gitconfig` file: Specific to your user. You can make Git read and write to this file specifically by passing the `--global` option. -* config file in the git directory (that is, `.git/config`) of whatever repository you’re currently using: Specific to that single repository. Each level overrides values in the previous level, so values in `.git/config` trump those in `/etc/gitconfig`. +* config file in the Git directory (that is, `.git/config`) of whatever repository you’re currently using: Specific to that single repository. Each level overrides values in the previous level, so values in `.git/config` trump those in `/etc/gitconfig`. On Windows systems, Git looks for the `.gitconfig` file in the `$HOME` directory (`%USERPROFILE%` in Windows’ environment), which is `C:\Documents and Settings\$USER` or `C:\Users\$USER` for most people, depending on version (`$USER` is `%USERNAME%` in Windows’ environment). It also still looks for /etc/gitconfig, although it’s relative to the MSys root, which is wherever you decide to install Git on your Windows system when you run the installer. diff --git a/en/02-git-basics/01-chapter2.markdown b/en/02-git-basics/01-chapter2.markdown index bbf48f64d..8737af541 100644 --- a/en/02-git-basics/01-chapter2.markdown +++ b/en/02-git-basics/01-chapter2.markdown @@ -54,8 +54,8 @@ Figure 2-1. The lifecycle of the status of your files. The main tool you use to determine which files are in which state is the `git status` command. If you run this command directly after a clone, you should see something like this: $ git status - # On branch master - nothing to commit (working directory clean) + On branch master + nothing to commit, working directory clean This means you have a clean working directory — in other words, no tracked files are modified. Git also doesn’t see any untracked files, or they would be listed here. Finally, the command tells you which branch you’re on. For now, that is always `master`, which is the default; you won’t worry about it here. The next chapter will go over branches and references in detail. @@ -63,11 +63,12 @@ Let’s say you add a new file to your project, a simple `README` file. If the f $ vim README $ git status - # On branch master - # Untracked files: - # (use "git add ..." to include in what will be committed) - # - # README + On branch master + Untracked files: + (use "git add ..." to include in what will be committed) + + README + nothing added to commit but untracked files present (use "git add" to track) You can see that your new `README` file is untracked, because it’s under the “Untracked files” heading in your status output. Untracked basically means that Git sees a file you didn’t have in the previous snapshot (commit); Git won’t start including it in your commit snapshots until you explicitly tell it to do so. It does this so you don’t accidentally begin including generated binary files or other files that you did not mean to include. You do want to start including README, so let’s start tracking the file. @@ -81,12 +82,12 @@ In order to begin tracking a new file, you use the command `git add`. To begin t If you run your status command again, you can see that your `README` file is now tracked and staged: $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README + You can tell that it’s staged because it’s under the “Changes to be committed” heading. If you commit at this point, the version of the file at the time you ran `git add` is what will be in the historical snapshot. You may recall that when you ran `git init` earlier, you then ran `git add (files)` — that was to begin tracking files in your directory. The `git add` command takes a path name for either a file or a directory; if it’s a directory, the command adds all the files in that directory recursively. @@ -95,58 +96,60 @@ You can tell that it’s staged because it’s under the “Changes to be commit Let’s change a file that was already tracked. If you change a previously tracked file called `benchmarks.rb` and then run your `status` command again, you get something that looks like this: $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + The `benchmarks.rb` file appears under a section named “Changes not staged for commit” — which means that a file that is tracked has been modified in the working directory but not yet staged. To stage it, you run the `git add` command (it’s a multipurpose command — you use it to begin tracking new files, to stage files, and to do other things like marking merge-conflicted files as resolved). Let’s run `git add` now to stage the `benchmarks.rb` file, and then run `git status` again: $ git add benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README + modified: benchmarks.rb + Both files are staged and will go into your next commit. At this point, suppose you remember one little change that you want to make in `benchmarks.rb` before you commit it. You open it again and make that change, and you’re ready to commit. However, let’s run `git status` one more time: $ vim benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # modified: benchmarks.rb - # - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README + modified: benchmarks.rb + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + What the heck? Now `benchmarks.rb` is listed as both staged and unstaged. How is that possible? It turns out that Git stages a file exactly as it is when you run the `git add` command. If you commit now, the version of `benchmarks.rb` as it was when you last ran the `git add` command is how it will go into the commit, not the version of the file as it looks in your working directory when you run `git commit`. If you modify a file after you run `git add`, you have to run `git add` again to stage the latest version of the file: $ git add benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README + modified: benchmarks.rb + ### Ignoring Files ### @@ -192,17 +195,18 @@ If the `git status` command is too vague for you — you want to know exactly wh Let’s say you edit and stage the `README` file again and then edit the `benchmarks.rb` file without staging it. If you run your `status` command, you once again see something like this: $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + To see what you’ve changed but not yet staged, type `git diff` with no other arguments: @@ -247,16 +251,18 @@ For another example, if you stage the `benchmarks.rb` file and then edit it, you $ git add benchmarks.rb $ echo '# test line' >> benchmarks.rb $ git status - # On branch master - # - # Changes to be committed: - # - # modified: benchmarks.rb - # - # Changes not staged for commit: - # - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: benchmarks.rb + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + Now you can use `git diff` to see what is still unstaged @@ -305,10 +311,9 @@ The editor displays the following text (this example is a Vim screen): # with '#' will be ignored, and an empty message aborts the commit. # On branch master # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # # new file: README # modified: benchmarks.rb + # ~ ~ ~ @@ -319,8 +324,8 @@ You can see that the default commit message contains the latest output of the `g Alternatively, you can type your commit message inline with the `commit` command by specifying it after a `-m` flag, like this: $ git commit -m "Story 182: Fix benchmarks for speed" - [master]: created 463dc4f: "Fix benchmarks for speed" - 2 files changed, 3 insertions(+), 0 deletions(-) + [master 463dc4f] Story 182: Fix benchmarks for speed + 2 files changed, 3 insertions(+) create mode 100644 README Now you’ve created your first commit! You can see that the commit has given you some output about itself: which branch you committed to (`master`), what SHA-1 checksum the commit has (`463dc4f`), how many files were changed, and statistics about lines added and removed in the commit. @@ -332,15 +337,17 @@ Remember that the commit records the snapshot you set up in your staging area. A Although it can be amazingly useful for crafting commits exactly how you want them, the staging area is sometimes a bit more complex than you need in your workflow. If you want to skip the staging area, Git provides a simple shortcut. Providing the `-a` option to the `git commit` command makes Git automatically stage every file that is already tracked before doing the commit, letting you skip the `git add` part: $ git status - # On branch master - # - # Changes not staged for commit: - # - # modified: benchmarks.rb - # + On branch master + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + + no changes added to commit (use "git add" and/or "git commit -a") $ git commit -a -m 'added new benchmarks' [master 83e38c7] added new benchmarks - 1 files changed, 5 insertions(+), 0 deletions(-) + 1 files changed, 5 insertions(+) Notice how you don’t have to run `git add` on the `benchmarks.rb` file in this case before you commit. @@ -352,26 +359,26 @@ If you simply remove the file from your working directory, it shows up under the $ rm grit.gemspec $ git status - # On branch master - # - # Changes not staged for commit: - # (use "git add/rm ..." to update what will be committed) - # - # deleted: grit.gemspec - # + On branch master + Changes not staged for commit: + (use "git add/rm ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + deleted: grit.gemspec + + no changes added to commit (use "git add" and/or "git commit -a") Then, if you run `git rm`, it stages the file’s removal: $ git rm grit.gemspec rm 'grit.gemspec' $ git status - # On branch master - # - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # deleted: grit.gemspec - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + deleted: grit.gemspec + The next time you commit, the file will be gone and no longer tracked. If you modified the file and added it to the index already, you must force the removal with the `-f` option. This is a safety feature to prevent accidental removal of data that hasn’t yet been recorded in a snapshot and that can’t be recovered from Git. @@ -399,22 +406,20 @@ Thus it’s a bit confusing that Git has a `mv` command. If you want to rename a and it works fine. In fact, if you run something like this and look at the status, you’ll see that Git considers it a renamed file: - $ git mv README.txt README + $ git mv README README.txt $ git status - # On branch master - # Your branch is ahead of 'origin/master' by 1 commit. - # - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # renamed: README.txt -> README - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + renamed: README -> README.txt + However, this is equivalent to running something like this: - $ mv README.txt README - $ git rm README.txt - $ git add README + $ mv README README.txt + $ git rm README + $ git add README.txt Git figures out that it’s a rename implicitly, so it doesn’t matter if you rename a file that way or with the `mv` command. The only real difference is that `mv` is one command instead of three — it’s a convenience function. More important, you can use any tool you like to rename a file, and address the add/rm later, before you commit. @@ -525,7 +530,7 @@ You can also use a series of summarizing options with `git log`. For example, if changed the version number Rakefile | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) + 1 file changed, 1 insertion(+), 1 deletion(-) commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 Author: Scott Chacon @@ -534,7 +539,7 @@ You can also use a series of summarizing options with `git log`. For example, if removed unnecessary test code lib/simplegit.rb | 5 ----- - 1 files changed, 0 insertions(+), 5 deletions(-) + 1 file changed, 5 deletions(-) commit a11bef06a3f659402fe7563abf99ad00de2209e6 Author: Scott Chacon @@ -545,7 +550,7 @@ You can also use a series of summarizing options with `git log`. For example, if README | 6 ++++++ Rakefile | 23 +++++++++++++++++++++++ lib/simplegit.rb | 25 +++++++++++++++++++++++++ - 3 files changed, 54 insertions(+), 0 deletions(-) + 3 files changed, 54 insertions(+) As you can see, the `--stat` option prints below each commit entry a list of modified files, how many files were changed, and how many lines in those files were added and removed. It also puts a summary of the information at the end. Another really useful option is `--pretty`. This option changes the log output to formats other than the default. A few prebuilt options are available for you to use. The `oneline` option prints each commit on a single line, which is useful if you’re looking at a lot of commits. In addition, the `short`, `full`, and `fuller` options show the output in roughly the same format but with less or more information, respectively: @@ -632,7 +637,9 @@ However, the time-limiting options such as `--since` and `--until` are very usef This command works with lots of formats — you can specify a specific date (“2008-01-15”) or a relative date such as “2 years 1 day 3 minutes ago”. -You can also filter the list to commits that match some search criteria. The `--author` option allows you to filter on a specific author, and the `--grep` option lets you search for keywords in the commit messages. (Note that if you want to specify both author and grep options, you have to add `--all-match` or the command will match commits with either.) +You can also filter the list to commits that match some search criteria. The `--author` option allows you to filter on a specific author, and the `--grep` option lets you search for keywords in the commit messages. (Note that if you specify both author and grep options, the command will match commits with both.) + +If you want to specify multiple grep options, you have to add `--all-match` or the command will match commits with either. The last really useful option to pass to `git log` as a filter is a path. If you specify a directory or file name, you can limit the log output to commits that introduced a change to those files. This is always the last option and is generally preceded by double dashes (`--`) to separate the paths from the options. @@ -645,15 +652,60 @@ The lines must be formatted as follows Option Description -(n) Show only the last n commits - --since, --after Limit the commits to those made after the specified date. - --until, --before Limit the commits to those made before the specified date. + --since, --after Limit the commits to those whose CommitDate was made on-or-after the specified date/time. + --until, --before Limit the commits to those whose CommitDate was made on-or-before the specified date/time. --author Only show commits in which the author entry matches the specified string. --committer Only show commits in which the committer entry matches the specified string. -For example, if you want to see which commits modifying test files in the Git source code history were committed by Junio Hamano in the month of October 2008 and were not merges, you can run something like this: - $ git log --pretty="%h - %s" --author=gitster --since="2008-10-01" \ - --before="2008-11-01" --no-merges -- t/ +### Limiting Log Output according to Date/Time ### + +To determine which commits in the Git source code repository (git://git.kernel.org/pub/scm/git/git.git) have CommitDate on 2014-04-29 relative to your local timezone (as set on your computer), use + + $ git log --after="2014-04-29 00:00:00" --before="2014-04-29 23:59:59" \ + --pretty=fuller + +As the output will be different according to the timezone where it will be run, it's recommended to always use an absolute time such as ISO 8601 format (which includes timezone information) as argument to `--after` and `--before`, so that everone running the command will get the same repeatable results. + +To obtain commits made at a specific instant in time (e.g. 29 April 2013 at 17:07:22 CET), we can use + + $ git log --after="2013-04-29T17:07:22+0200" \ + --before="2013-04-29T17:07:22+0200" --pretty=fuller + + commit de7c201a10857e5d424dbd8db880a6f24ba250f9 + Author: Ramkumar Ramachandra + AuthorDate: Mon Apr 29 18:19:37 2013 +0530 + Commit: Junio C Hamano + CommitDate: Mon Apr 29 08:07:22 2013 -0700 + + git-completion.bash: lexical sorting for diff.statGraphWidth + + df44483a (diff --stat: add config option to limit graph width, + 2012-03-01) added the option diff.startGraphWidth to the list of + configuration variables in git-completion.bash, but failed to notice + that the list is sorted alphabetically. Move it to its rightful place + in the list. + + Signed-off-by: Ramkumar Ramachandra + Signed-off-by: Junio C Hamano + +The above times (`AuthorDate`, `CommitDate`) are displayed in default format (`--date=default`), which shows timezone information of respective author and commiter. + +Other useful formats include `--date=iso` (ISO 8601), `--date=rfc` (RFC 2822), `--date=raw` (seconds since the epoch (1970-01-01 UTC)) `--date=local` (times according to your local timezone) as well as `--date=relative` (e.g. "2 hours ago"). + +When using `git log` without specifying time, the time defaults to the time at which the command is run on your computer (keeping the identical offset from UTC). + +For example, running a `git log` at 09:00 on your computer with your timezone currently 3 hours ahead of UTC, makes the following two commands equivalent: + + $ git log --after=2008-06-01 --before=2008-07-01 + $ git log --after="2008-06-01T09:00:00+0300" \ + --before="2008-07-01T09:00:00+0300" + +As a final example, if you want to see which commits modifying test files in the Git source code history were committed by Junio Hamano with CommitDate being in the month of October 2008 (relative to the timezone of New York) and were not merges, you can run something like this: + + $ git log --pretty="%h - %s" --author=gitster \ + --after="2008-10-01T00:00:00-0400" \ + --before="2008-10-31T23:59:59-0400" --no-merges -- t/ 5610e3b - Fix testcase failure when extended attribute acd3b9e - Enhance hold_lock_file_for_{update,append}() f563754 - demonstrate breakage of detached checkout wi @@ -661,7 +713,7 @@ For example, if you want to see which commits modifying test files in the Git so 51a94af - Fix "checkout --track -b newbranch" on detac b0ad11e - pull: allow "git pull origin $something:$cur -Of the nearly 20,000 commits in the Git source code history, this command shows the 6 that match those criteria. +Of the more than 36,000 commits in the Git source code history, this command shows the 6 that match those criteria. ### Using a GUI to Visualize History ### @@ -700,31 +752,32 @@ The next two sections demonstrate how to wrangle your staging area and working d $ git add . $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # modified: README.txt - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: README.txt + modified: benchmarks.rb + Right below the “Changes to be committed” text, it says "use `git reset HEAD ...` to unstage". So, let’s use that advice to unstage the `benchmarks.rb` file: $ git reset HEAD benchmarks.rb - benchmarks.rb: locally modified + Unstaged changes after reset: + M benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # modified: README.txt - # - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # (use "git checkout -- ..." to discard changes in working directory) - # - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: README.txt + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + The command is a bit strange, but it works. The `benchmarks.rb` file is modified but once again unstaged. @@ -732,23 +785,23 @@ The command is a bit strange, but it works. The `benchmarks.rb` file is modified What if you realize that you don’t want to keep your changes to the `benchmarks.rb` file? How can you easily unmodify it — revert it back to what it looked like when you last committed (or initially cloned, or however you got it into your working directory)? Luckily, `git status` tells you how to do that, too. In the last example output, the unstaged area looks like this: - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # (use "git checkout -- ..." to discard changes in working directory) - # - # modified: benchmarks.rb - # + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + It tells you pretty explicitly how to discard the changes you’ve made (at least, the newer versions of Git, 1.6.1 and later, do this — if you have an older version, we highly recommend upgrading it to get some of these nicer usability features). Let’s do what it says: $ git checkout -- benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # modified: README.txt - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: README.txt + You can see that the changes have been reverted. You should also realize that this is a dangerous command: any changes you made to that file are gone — you just copied another file over it. Don’t ever use this command unless you absolutely know that you don’t want the file. If you just need to get it out of the way, we’ll go over stashing and branching in the next chapter; these are generally better ways to go. @@ -764,12 +817,12 @@ Managing remote repositories includes knowing how to add remote repositories, re To see which remote servers you have configured, you can run the `git remote` command. It lists the shortnames of each remote handle you’ve specified. If you’ve cloned your repository, you should at least see *origin* — that is the default name Git gives to the server you cloned from: $ git clone git://github.com/schacon/ticgit.git - Initialized empty Git repository in /private/tmp/ticgit/.git/ - remote: Counting objects: 595, done. - remote: Compressing objects: 100% (269/269), done. - remote: Total 595 (delta 255), reused 589 (delta 253) - Receiving objects: 100% (595/595), 73.31 KiB | 1 KiB/s, done. - Resolving deltas: 100% (255/255), done. + Cloning into 'ticgit'... + remote: Reusing existing pack: 1857, done. + remote: Total 1857 (delta 0), reused 0 (delta 0) + Receiving objects: 100% (1857/1857), 374.35 KiB | 193.00 KiB/s, done. + Resolving deltas: 100% (772/772), done. + Checking connectivity... done. $ cd ticgit $ git remote origin @@ -790,7 +843,7 @@ If you have more than one remote, the command lists them all. For example, my Gr koke git://github.com/koke/grit.git origin git@github.com:mojombo/grit.git -This means we can pull contributions from any of these users pretty easily. But notice that only the origin remote is an SSH URL, so it’s the only one I can push to (we’ll cover why this is in *Chapter 4*). +This means I can pull contributions from any of these users pretty easily. But notice that only the origin remote is an SSH URL, so it’s the only one I can push to (we’ll cover why this is in *Chapter 4*). ### Adding Remote Repositories ### @@ -940,6 +993,7 @@ You can see the tag data along with the commit that was tagged by using the `git Date: Mon Feb 9 14:45:11 2009 -0800 my version 1.4 + commit 15027957951b64cf874c3557a0f3547bd83b3ff6 Merge: 4a447f7... a6b4c97... Author: Scott Chacon @@ -1122,8 +1176,11 @@ In this case, typing `git co` and then pressing the Tab key twice suggests commi This also works with options, which is probably more useful. For instance, if you’re running a `git log` command and can’t remember one of the options, you can start typing it and press Tab to see what matches: - $ git log --s - --shortstat --since= --src-prefix= --stat --summary + $ git log --s + --shortstat --sparse + --simplify-by-decoration --src-prefix= + --simplify-merges --stat + --since= --summary That’s a pretty nice trick and may save you some time and documentation reading. diff --git a/en/03-git-branching/01-chapter3.markdown b/en/03-git-branching/01-chapter3.markdown index 8924dbe5e..3d63b2577 100644 --- a/en/03-git-branching/01-chapter3.markdown +++ b/en/03-git-branching/01-chapter3.markdown @@ -41,7 +41,7 @@ This creates a new pointer at the same commit you’re currently on (see Figure Insert 18333fig0304.png Figure 3-4. Multiple branches pointing into the commit’s data history. -How does Git know what branch you’re currently on? It keeps a special pointer called HEAD. Note that this is a lot different than the concept of HEAD in other VCSs you may be used to, such as Subversion or CVS. In Git, this is a pointer to the local branch you’re currently on. In this case, you’re still on master. The git branch command only created a new branch — it didn’t switch to that branch (see Figure 3-5). +How does Git know what branch you’re currently on? It keeps a special pointer called HEAD. Note that this is a lot different than the concept of HEAD in other VCSs you may be used to, such as Subversion or CVS. In Git, this is a pointer to the local branch you’re currently on. In this case, you’re still on master. The `git branch` command only created a new branch — it didn’t switch to that branch (see Figure 3-5). Insert 18333fig0305.png Figure 3-5. HEAD file pointing to the branch you’re on. @@ -102,7 +102,7 @@ Let’s go through a simple example of branching and merging with a workflow tha At this stage, you’ll receive a call that another issue is critical and you need a hotfix. You’ll do the following: -1. Revert back to your production branch. +1. Switch back to your production branch. 2. Create a branch to add the hotfix. 3. After it’s tested, merge the hotfix branch, and push to production. 4. Switch back to your original story and continue working. @@ -117,7 +117,7 @@ Figure 3-10. A short and simple commit history. You’ve decided that you’re going to work on issue #53 in whatever issue-tracking system your company uses. To be clear, Git isn’t tied into any particular issue-tracking system; but because issue #53 is a focused topic that you want to work on, you’ll create a new branch in which to work. To create a branch and switch to it at the same time, you can run the `git checkout` command with the `-b` switch: $ git checkout -b iss53 - Switched to a new branch "iss53" + Switched to a new branch 'iss53' This is shorthand for: @@ -132,7 +132,7 @@ Figure 3-11. Creating a new branch pointer. You work on your web site and do some commits. Doing so moves the `iss53` branch forward, because you have it checked out (that is, your HEAD is pointing to it; see Figure 3-12): $ vim index.html - $ git commit -a -m 'added a new footer [issue 53]' + $ git commit -a -m 'add a new footer [issue 53]' Insert 18333fig0312.png Figure 3-12. The iss53 branch has moved forward with your work. @@ -142,18 +142,18 @@ Now you get the call that there is an issue with the web site, and you need to f However, before you do that, note that if your working directory or staging area has uncommitted changes that conflict with the branch you’re checking out, Git won’t let you switch branches. It’s best to have a clean working state when you switch branches. There are ways to get around this (namely, stashing and commit amending) that we’ll cover later. For now, you’ve committed all your changes, so you can switch back to your master branch: $ git checkout master - Switched to branch "master" + Switched to branch 'master' At this point, your project working directory is exactly the way it was before you started working on issue #53, and you can concentrate on your hotfix. This is an important point to remember: Git resets your working directory to look like the snapshot of the commit that the branch you check out points to. It adds, removes, and modifies files automatically to make sure your working copy is what the branch looked like on your last commit to it. Next, you have a hotfix to make. Let’s create a hotfix branch on which to work until it’s completed (see Figure 3-13): $ git checkout -b hotfix - Switched to a new branch "hotfix" + Switched to a new branch 'hotfix' $ vim index.html - $ git commit -a -m 'fixed the broken email address' - [hotfix]: created 3a0874c: "fixed the broken email address" - 1 files changed, 0 insertions(+), 1 deletions(-) + $ git commit -a -m 'fix the broken email address' + [hotfix 3a0874c] fix the broken email address + 1 files changed, 1 deletion(-) Insert 18333fig0313.png Figure 3-13. hotfix branch based back at your master branch point. @@ -163,11 +163,11 @@ You can run your tests, make sure the hotfix is what you want, and merge it back $ git checkout master $ git merge hotfix Updating f42c576..3a0874c - Fast forward - README | 1 - - 1 files changed, 0 insertions(+), 1 deletions(-) + Fast-forward + README | 1 - + 1 file changed, 1 deletion(-) -You’ll notice the phrase "Fast forward" in that merge. Because the commit pointed to by the branch you merged in was directly upstream of the commit you’re on, Git moves the pointer forward. To phrase that another way, when you try to merge one commit with a commit that can be reached by following the first commit’s history, Git simplifies things by moving the pointer forward because there is no divergent work to merge together — this is called a "fast forward". +You’ll notice the phrase "Fast-forward" in that merge. Because the commit pointed to by the branch you merged in was directly upstream of the commit you’re on, Git moves the pointer forward. To phrase that another way, when you try to merge one commit with a commit that can be reached by following the first commit’s history, Git simplifies things by moving the pointer forward because there is no divergent work to merge together — this is called a "fast forward". Your change is now in the snapshot of the commit pointed to by the `master` branch, and you can deploy your change (see Figure 3-14). @@ -177,16 +177,16 @@ Figure 3-14. Your master branch points to the same place as your hotfix branch a After your super-important fix is deployed, you’re ready to switch back to the work you were doing before you were interrupted. However, first you’ll delete the `hotfix` branch, because you no longer need it — the `master` branch points at the same place. You can delete it with the `-d` option to `git branch`: $ git branch -d hotfix - Deleted branch hotfix (3a0874c). + Deleted branch hotfix (was 3a0874c). Now you can switch back to your work-in-progress branch on issue #53 and continue working on it (see Figure 3-15): $ git checkout iss53 - Switched to branch "iss53" + Switched to branch 'iss53' $ vim index.html - $ git commit -a -m 'finished the new footer [issue 53]' - [iss53]: created ad82d7a: "finished the new footer [issue 53]" - 1 files changed, 1 insertions(+), 0 deletions(-) + $ git commit -a -m 'finish the new footer [issue 53]' + [iss53 ad82d7a] finish the new footer [issue 53] + 1 file changed, 1 insertion(+) Insert 18333fig0315.png Figure 3-15. Your iss53 branch can move forward independently. @@ -199,9 +199,10 @@ Suppose you’ve decided that your issue #53 work is complete and ready to be me $ git checkout master $ git merge iss53 - Merge made by recursive. - README | 1 + - 1 files changed, 1 insertions(+), 0 deletions(-) + Auto-merging README + Merge made by the 'recursive' strategy. + README | 1 + + 1 file changed, 1 insertion(+) This looks a bit different than the `hotfix` merge you did earlier. In this case, your development history has diverged from some older point. Because the commit on the branch you’re on isn’t a direct ancestor of the branch you’re merging in, Git has to do some work. In this case, Git does a simple three-way merge, using the two snapshots pointed to by the branch tips and the common ancestor of the two. Figure 3-16 highlights the three snapshots that Git uses to do its merge in this case. @@ -230,25 +231,27 @@ Occasionally, this process doesn’t go smoothly. If you changed the same part o Git hasn’t automatically created a new merge commit. It has paused the process while you resolve the conflict. If you want to see which files are unmerged at any point after a merge conflict, you can run `git status`: - [master*]$ git status - index.html: needs merge - # On branch master - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # (use "git checkout -- ..." to discard changes in working directory) - # - # unmerged: index.html - # + $ git status + On branch master + You have unmerged paths. + (fix conflicts and run "git commit") + + Unmerged paths: + (use "git add ..." to mark resolution) + + both modified: index.html + + no changes added to commit (use "git add" and/or "git commit -a") Anything that has merge conflicts and hasn’t been resolved is listed as unmerged. Git adds standard conflict-resolution markers to the files that have conflicts, so you can open them manually and resolve those conflicts. Your file contains a section that looks something like this: - <<<<<<< HEAD:index.html + <<<<<<< HEAD ======= - >>>>>>> iss53:index.html + >>>>>>> iss53 This means the version in HEAD (your master branch, because that was what you had checked out when you ran your merge command) is the top part of that block (everything above the `=======`), while the version in your `iss53` branch looks like everything in the bottom part. In order to resolve the conflict, you have to either choose one side or the other or merge the contents yourself. For instance, you might resolve this conflict by replacing the entire block with this: @@ -260,27 +263,32 @@ This resolution has a little of each section, and I’ve fully removed the `<<<< If you want to use a graphical tool to resolve these issues, you can run `git mergetool`, which fires up an appropriate visual merge tool and walks you through the conflicts: $ git mergetool - merge tool candidates: kdiff3 tkdiff xxdiff meld gvimdiff opendiff emerge vimdiff - Merging the files: index.html + + This message is displayed because 'merge.tool' is not configured. + See 'git mergetool --tool-help' or 'git help config' for more details. + 'git mergetool' will now attempt to use one of the following tools: + opendiff kdiff3 tkdiff xxdiff meld tortoisemerge gvimdiff diffuse diffmerge ecmerge p4merge araxis bc3 codecompare vimdiff emerge + Merging: + index.html Normal merge conflict for 'index.html': - {local}: modified - {remote}: modified + {local}: modified file + {remote}: modified file Hit return to start merge resolution tool (opendiff): -If you want to use a merge tool other than the default (Git chose `opendiff` for me in this case because I ran the command on a Mac), you can see all the supported tools listed at the top after “merge tool candidates”. Type the name of the tool you’d rather use. In Chapter 7, we’ll discuss how you can change this default value for your environment. +If you want to use a merge tool other than the default (Git chose `opendiff` for me in this case because I ran the command on a Mac), you can see all the supported tools listed at the top after “... one of the following tools:”. Type the name of the tool you’d rather use. In Chapter 7, we’ll discuss how you can change this default value for your environment. After you exit the merge tool, Git asks you if the merge was successful. If you tell the script that it was, it stages the file to mark it as resolved for you. You can run `git status` again to verify that all conflicts have been resolved: $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # modified: index.html - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: index.html + If you’re happy with that, and you verify that everything that had conflicts has been staged, you can type `git commit` to finalize the merge commit. The commit message by default looks something like this: @@ -289,9 +297,9 @@ If you’re happy with that, and you verify that everything that had conflicts h Conflicts: index.html # - # It looks like you may be committing a MERGE. + # It looks like you may be committing a merge. # If this is not correct, please remove the file - # .git/MERGE_HEAD + # .git/MERGE_HEAD # and try again. # @@ -331,7 +339,7 @@ To see all the branches that contain work you haven’t yet merged in, you can r This shows your other branch. Because it contains work that isn’t merged in yet, trying to delete it with `git branch -d` will fail: $ git branch -d testing - error: The branch 'testing' is not an ancestor of your current HEAD. + error: The branch 'testing' is not fully merged. If you are sure you want to delete it, run 'git branch -D testing'. If you really do want to delete the branch and lose that work, you can force it with `-D`, as the helpful message points out. @@ -396,7 +404,7 @@ Figure 3-23. Working locally and having someone push to your remote server makes To synchronize your work, you run a `git fetch origin` command. This command looks up which server origin is (in this case, it’s `git.ourcompany.com`), fetches any data from it that you don’t yet have, and updates your local database, moving your `origin/master` pointer to its new, more up-to-date position (see Figure 3-24). Insert 18333fig0324.png -Figure 3-24. The git fetch command updates your remote references. +Figure 3-24. The `git fetch` command updates your remote references. To demonstrate having multiple remote servers and what remote branches for those remote projects look like, let’s assume you have another internal Git server that is used only for development by one of your sprint teams. This server is at `git.team1.ourcompany.com`. You can add it as a new remote reference to the project you’re currently working on by running the `git remote add` command as we covered in Chapter 2. Name this remote `teamone`, which will be your shortname for that whole URL (see Figure 3-25). @@ -439,8 +447,8 @@ It’s important to note that when you do a fetch that brings down new remote br To merge this work into your current working branch, you can run `git merge origin/serverfix`. If you want your own `serverfix` branch that you can work on, you can base it off your remote branch: $ git checkout -b serverfix origin/serverfix - Branch serverfix set up to track remote branch refs/remotes/origin/serverfix. - Switched to a new branch "serverfix" + Branch serverfix set up to track remote branch serverfix from origin. + Switched to a new branch 'serverfix' This gives you a local branch that you can work on that starts where `origin/serverfix` is. @@ -451,16 +459,16 @@ Checking out a local branch from a remote branch automatically creates what is c When you clone a repository, it generally automatically creates a `master` branch that tracks `origin/master`. That’s why `git push` and `git pull` work out of the box with no other arguments. However, you can set up other tracking branches if you wish — ones that don’t track branches on `origin` and don’t track the `master` branch. The simple case is the example you just saw, running `git checkout -b [branch] [remotename]/[branch]`. If you have Git version 1.6.2 or later, you can also use the `--track` shorthand: $ git checkout --track origin/serverfix - Branch serverfix set up to track remote branch refs/remotes/origin/serverfix. - Switched to a new branch "serverfix" + Branch serverfix set up to track remote branch serverfix from origin. + Switched to a new branch 'serverfix' To set up a local branch with a different name than the remote branch, you can easily use the first version with a different local branch name: $ git checkout -b sf origin/serverfix - Branch sf set up to track remote branch refs/remotes/origin/serverfix. - Switched to a new branch "sf" + Branch sf set up to track remote branch serverfix from origin. + Switched to a new branch 'sf' -Now, your local branch sf will automatically push to and pull from origin/serverfix. +Now, your local branch `sf` will automatically push to and pull from `origin/serverfix`. ### Deleting Remote Branches ### diff --git a/en/04-git-server/01-chapter4.markdown b/en/04-git-server/01-chapter4.markdown index af7665115..e4022c1b0 100644 --- a/en/04-git-server/01-chapter4.markdown +++ b/en/04-git-server/01-chapter4.markdown @@ -26,7 +26,7 @@ Or you can do this: $ git clone file:///opt/git/project.git -Git operates slightly differently if you explicitly specify `file://` at the beginning of the URL. If you just specify the path, Git tries to use hardlinks or directly copy the files it needs. If you specify `file://`, Git fires up the processes that it normally uses to transfer data over a network which is generally a lot less efficient method of transferring the data. The main reason to specify the `file://` prefix is if you want a clean copy of the repository with extraneous references or objects left out — generally after an import from another version-control system or something similar (see Chapter 9 for maintenance tasks). We’ll use the normal path here because doing so is almost always faster. +Git operates slightly differently if you explicitly specify `file://` at the beginning of the URL. If you just specify the path, and the source and the destination are on the same filesystem, Git tries to hardlink the objects it needs. If they are not on the same filesystem, it will copy the objects it needs using the system's standard copying functionality. If you specify `file://`, Git fires up the processes that it normally uses to transfer data over a network which is generally a lot less efficient method of transferring the data. The main reason to specify the `file://` prefix is if you want a clean copy of the repository with extraneous references or objects left out — generally after an import from another version-control system or something similar (see Chapter 9 for maintenance tasks). We’ll use the normal path here because doing so is almost always faster. To add a local repository to an existing Git project, you can run something like this: @@ -70,7 +70,7 @@ The negative aspect of SSH is that you can’t serve anonymous access of your re ### The Git Protocol ### -Next is the Git protocol. This is a special daemon that comes packaged with Git; it listens on a dedicated port (9418) that provides a service similar to the SSH protocol, but with absolutely no authentication. In order for a repository to be served over the Git protocol, you must create the `git-export-daemon-ok` file — the daemon won’t serve a repository without that file in it — but other than that there is no security. Either the Git repository is available for everyone to clone or it isn’t. This means that there is generally no pushing over this protocol. You can enable push access; but given the lack of authentication, if you turn on push access, anyone on the internet who finds your project’s URL could push to your project. Suffice it to say that this is rare. +Next is the Git protocol. This is a special daemon that comes packaged with Git; it listens on a dedicated port (9418) that provides a service similar to the SSH protocol, but with absolutely no authentication. In order for a repository to be served over the Git protocol, you must create the `git-daemon-export-ok` file — the daemon won’t serve a repository without that file in it — but other than that there is no security. Either the Git repository is available for everyone to clone or it isn’t. This means that there is generally no pushing over this protocol. You can enable push access; but given the lack of authentication, if you turn on push access, anyone on the internet who finds your project’s URL could push to your project. Suffice it to say that this is rare. #### The Pros #### @@ -117,9 +117,10 @@ In order to initially set up any Git server, you have to export an existing repo In order to clone your repository to create a new bare repository, you run the clone command with the `--bare` option. By convention, bare repository directories end in `.git`, like so: $ git clone --bare my_project my_project.git - Initialized empty Git repository in /opt/projects/my_project.git/ + Cloning into bare repository 'my_project.git'... + done. -The output for this command is a little confusing. Since `clone` is basically a `git init` then a `git fetch`, we see some output from the `git init` part, which creates an empty directory. The actual object transfer gives no output, but it does happen. You should now have a copy of the Git directory data in your `my_project.git` directory. +You should now have a copy of the Git directory data in your `my_project.git` directory. This is roughly equivalent to something like @@ -226,7 +227,11 @@ You just append them to your `authorized_keys` file: $ cat /tmp/id_rsa.josie.pub >> ~/.ssh/authorized_keys $ cat /tmp/id_rsa.jessica.pub >> ~/.ssh/authorized_keys -Now, you can set up an empty repository for them by running `git init` with the `--bare` option, which initializes the repository without a working directory: +Key-based SSH authentication usually enforces security by requiring restricted rights on the involved files. To prevent SSH from refusing to work, type this: + + $ chmod -R go= ~/.ssh + +Now, you can set up an empty repository for your users by running `git init` with the `--bare` option, which initializes the repository without a working directory: $ cd /opt/git $ mkdir project.git @@ -287,6 +292,13 @@ What does this `post-update` hook do? It looks basically like this: $ cat .git/hooks/post-update #!/bin/sh + # + # An example hook script to prepare a packed repository for use over + # dumb transports. + # + # To enable this hook, rename this file to "post-update". + # + exec git-update-server-info This means that when you push to the server via SSH, Git will run this command to update the files needed for HTTP fetching. @@ -368,7 +380,7 @@ Gitosis requires some Python tools, so first you have to install the Python setu Next, you clone and install Gitosis from the project’s main site: - $ git clone git://eagain.net/gitosis.git + $ git clone https://github.com/tv42/gitosis.git $ cd gitosis $ sudo python setup.py install @@ -402,7 +414,7 @@ You’re ready to roll. If you’re set up correctly, you can try to SSH into yo $ ssh git@gitserver PTY allocation request failed on channel 0 - fatal: unrecognized command 'gitosis-serve schacon@quaternion' + ERROR:gitosis.serve.main:Need SSH_ORIGINAL_COMMAND in environment. Connection to gitserver closed. That means Gitosis recognized you but shut you out because you’re not trying to do any Git commands. So, let’s do an actual Git command — you’ll clone the Gitosis control repository: @@ -426,28 +438,28 @@ If you look at the `gitosis.conf` file, it should only specify information about [gitosis] [group gitosis-admin] - writable = gitosis-admin members = scott + writable = gitosis-admin It shows you that the 'scott' user — the user with whose public key you initialized Gitosis — is the only one who has access to the `gitosis-admin` project. Now, let’s add a new project for you. You’ll add a new section called `mobile` where you’ll list the developers on your mobile team and projects that those developers need access to. Because 'scott' is the only user in the system right now, you’ll add him as the only member, and you’ll create a new project called `iphone_project` to start on: [group mobile] - writable = iphone_project members = scott + writable = iphone_project Whenever you make changes to the `gitosis-admin` project, you have to commit the changes and push them back up to the server in order for them to take effect: $ git commit -am 'add iphone_project and mobile group' - [master]: created 8962da8: "changed name" - 1 files changed, 4 insertions(+), 0 deletions(-) - $ git push + [master 8962da8] add iphone_project and mobile group + 1 file changed, 4 insertions(+) + $ git push origin master Counting objects: 5, done. - Compressing objects: 100% (2/2), done. - Writing objects: 100% (3/3), 272 bytes, done. - Total 3 (delta 1), reused 0 (delta 0) - To git@gitserver:/opt/git/gitosis-admin.git + Compressing objects: 100% (3/3), done. + Writing objects: 100% (3/3), 272 bytes | 0 bytes/s, done. + Total 3 (delta 0), reused 0 (delta 0) + To git@gitserver:gitosis-admin.git fb27aec..8962da8 master -> master You can make your first push to the new `iphone_project` project by adding your server as a remote to your local version of the project and pushing. You no longer have to manually create a bare repository for new projects on the server — Gitosis creates them automatically when it sees the first push: @@ -456,7 +468,7 @@ You can make your first push to the new `iphone_project` project by adding your $ git push origin master Initialized empty Git repository in /opt/git/iphone_project.git/ Counting objects: 3, done. - Writing objects: 100% (3/3), 230 bytes, done. + Writing objects: 100% (3/3), 230 bytes | 0 bytes/s, done. Total 3 (delta 0), reused 0 (delta 0) To git@gitserver:iphone_project.git * [new branch] master -> master @@ -472,20 +484,20 @@ You want to work on this project with your friends, so you’ll have to re-add t Now you can add them all to your 'mobile' team so they have read and write access to `iphone_project`: [group mobile] - writable = iphone_project members = scott john josie jessica + writable = iphone_project After you commit and push that change, all four users will be able to read from and write to that project. Gitosis has simple access controls as well. If you want John to have only read access to this project, you can do this instead: [group mobile] - writable = iphone_project members = scott josie jessica + writable = iphone_project [group mobile_ro] - readonly = iphone_project members = john + readonly = iphone_project Now John can clone the project and get updates, but Gitosis won’t allow him to push back up to the project. You can create as many of these groups as you want, each containing different users and projects. You can also specify another group as one of the members (using `@` as prefix), to inherit all of its members automatically: @@ -493,12 +505,12 @@ Now John can clone the project and get updates, but Gitosis won’t allow him to members = scott josie jessica [group mobile] - writable = iphone_project members = @mobile_committers + writable = iphone_project [group mobile_2] - writable = another_iphone_project members = @mobile_committers john + writable = another_iphone_project If you have any issues, it may be useful to add `loglevel=DEBUG` under the `[gitosis]` section. If you’ve lost push access by pushing a messed-up configuration, you can manually fix the file on the server under `/home/git/.gitosis.conf` — the file from which Gitosis reads its info. A push to the project takes the `gitosis.conf` file you just pushed up and sticks it there. If you edit that file manually, it remains like that until the next successful push to the `gitosis-admin` project. @@ -589,7 +601,7 @@ That rule will just get added to the ruleset for the `gitolite` repository. At this point you might be wondering how the access control rules are actually applied, so let’s go over that briefly. -There are two levels of access control in Gitolite. The first is at the repository level; if you have read (or write) access to *any* ref in the repository, then you have read (or write) access to the repository. This is the only access control that Gitosis had. +There are two levels of access control in Gitolite. The first is at the repository level; if you have read (or write) access to *any* ref in the repository, then you have read (or write) access to the repository. The second level, applicable only to "write" access, is by branch or tag within a repository. The username, the access being attempted (`W` or `+`), and the refname being updated are known. The access rules are checked in order of appearance in the config file, looking for a match for this combination (but remember that the refname is regex-matched, not merely string-matched). If a match is found, the push succeeds. A fallthrough results in access being denied. @@ -614,7 +626,7 @@ In addition to restricting what branches a user can push changes to, you can als - VREF/NAME/Makefile = @junior_devs -User who are migrating from the older Gitolite should note that there is a significant change in behaviour with regard to this feature; please see the migration guide for details. +Users who are migrating from the older Gitolite should note that there is a significant change in behaviour with regard to this feature; please see the migration guide for details. ### Personal Branches ### @@ -730,13 +742,13 @@ GitHub is by far the largest open source Git hosting site and it’s also one of ### GitHub ### -GitHub is slightly different than most code-hosting sites in the way that it namespaces projects. Instead of being primarily based on the project, GitHub is user centric. That means when I host my `grit` project on GitHub, you won’t find it at `github.com/grit` but instead at `github.com/schacon/grit`. There is no canonical version of any project, which allows a project to move from one user to another seamlessly if the first author abandons the project. +GitHub is slightly different than most code-hosting sites in the way that it namespaces projects. Instead of being primarily based on the project, GitHub is user-centric. That means when I host my `grit` project on GitHub, you won’t find it at `github.com/grit` but instead at `github.com/schacon/grit`. There is no canonical version of any project, which allows a project to move from one user to another seamlessly if the first author abandons the project. GitHub is also a commercial company that charges for accounts that maintain private repositories, but anyone can quickly get a free account to host as many open source projects as they want. We’ll quickly go over how that is done. ### Setting Up a User Account ### -The first thing you need to do is set up a free user account. If you visit the Pricing and Signup page at `http://github.com/plans` and click the "Sign Up" button on the Free account (see Figure 4-2), you’re taken to the signup page. +The first thing you need to do is set up a free user account. If you visit the "Plans and pricing" page at `https://github.com/pricing` and click the "Sign Up" button on the Free account (see Figure 4-2), you’re taken to the signup page. Insert 18333fig0402.png Figure 4-2. The GitHub plan page. diff --git a/en/05-distributed-git/01-chapter5.markdown b/en/05-distributed-git/01-chapter5.markdown index 6bf3e1d49..bb6a633e4 100644 --- a/en/05-distributed-git/01-chapter5.markdown +++ b/en/05-distributed-git/01-chapter5.markdown @@ -22,7 +22,7 @@ This workflow is attractive to a lot of people because it’s a paradigm that ma ### Integration-Manager Workflow ### -Because Git allows you to have multiple remote repositories, it’s possible to have a workflow where each developer has write access to their own public repository and read access to everyone else’s. This scenario often includes a canonical repository that represents the "official" project. To contribute to that project, you create your own public clone of the project and push your changes to it. Then, you can send a request to the maintainer of the main project to pull in your changes. They can add your repository as a remote, test your changes locally, merge them into their branch, and push back to their repository. The process works as follow (see Figure 5-2): +Because Git allows you to have multiple remote repositories, it’s possible to have a workflow where each developer has write access to their own public repository and read access to everyone else’s. This scenario often includes a canonical repository that represents the "official" project. To contribute to that project, you create your own public clone of the project and push your changes to it. Then, you can send a request to the maintainer of the main project to pull in your changes. They can add your repository as a remote, test your changes locally, merge them into their branch, and push back to their repository. The process works as follows (see Figure 5-2): 1. The project maintainer pushes to their public repository. 2. A contributor clones that repository and makes changes. @@ -174,7 +174,7 @@ John has a reference to the changes Jessica pushed up, but he has to merge them The merge goes smoothly — John’s commit history now looks like Figure 5-5. Insert 18333fig0505.png -Figure 5-5. John’s repository after merging origin/master. +Figure 5-5. John’s repository after merging `origin/master`. Now, John can test his code to make sure it still works properly, and then he can push his new merged work up to the server: @@ -215,7 +215,7 @@ Jessica thinks her topic branch is ready, but she wants to know what she has to removed invalid default value -Now, Jessica can merge her topic work into her master branch, merge John’s work (`origin/master`) into her `master` branch, and then push back to the server again. First, she switches back to her master branch to integrate all this work: +Now, Jessica can merge her topic work into her `master` branch, merge John’s work (`origin/master`) into her `master` branch, and then push back to the server again. First, she switches back to her `master` branch to integrate all this work: $ git checkout master Switched to branch "master" @@ -255,7 +255,7 @@ Each developer has committed a few times and merged each other’s work successf Insert 18333fig0510.png Figure 5-10. Jessica’s history after pushing all changes back to the server. -That is one of the simplest workflows. You work for a while, generally in a topic branch, and merge into your master branch when it’s ready to be integrated. When you want to share that work, you merge it into your own master branch, then fetch and merge `origin/master` if it has changed, and finally push to the `master` branch on the server. The general sequence is something like that shown in Figure 5-11. +That is one of the simplest workflows. You work for a while, generally in a topic branch, and merge into your `master` branch when it’s ready to be integrated. When you want to share that work, you merge it into your own `master` branch, then fetch and merge `origin/master` if it has changed, and finally push to the `master` branch on the server. The general sequence is something like that shown in Figure 5-11. Insert 18333fig0511.png Figure 5-11. General sequence of events for a simple multiple-developer Git workflow. @@ -532,7 +532,26 @@ First, you need to set up the imap section in your `~/.gitconfig` file. You can sslverify = false If your IMAP server doesn’t use SSL, the last two lines probably aren’t necessary, and the host value will be `imap://` instead of `imaps://`. -When that is set up, you can use `git send-email` to place the patch series in the Drafts folder of the specified IMAP server: +When that is set up, you can use `git imap-send` to place the patch series in the Drafts folder of the specified IMAP server: + + $ cat *.patch |git imap-send + Resolving imap.gmail.com... ok + Connecting to [74.125.142.109]:993... ok + Logging in... + sending 2 messages + 100% (2/2) done + +At this point, you should be able to go to your Drafts folder, change the To field to the mailing list you’re sending the patch to, possibly CC the maintainer or person responsible for that section, and send it off. + +You can also send the patches through an SMTP server. As before, you can set each value separately with a series of `git config` commands, or you can add them manually in the sendemail section in your `~/.gitconfig` file: + + [sendemail] + smtpencryption = tls + smtpserver = smtp.gmail.com + smtpuser = user@gmail.com + smtpserverport = 587 + +After this is done, you can use `git send-email` to send your patches: $ git send-email *.patch 0001-added-limit-to-log-function.patch @@ -559,8 +578,6 @@ Then, Git spits out a bunch of log information looking something like this for e Result: OK -At this point, you should be able to go to your Drafts folder, change the To field to the mailing list you’re sending the patch to, possibly CC the maintainer or person responsible for that section, and send it off. - ### Summary ### This section has covered a number of common workflows for dealing with several very different types of Git projects you’re likely to encounter and introduced a couple of new tools to help you manage this process. Next, you’ll see how to work the other side of the coin: maintaining a Git project. You’ll learn how to be a benevolent dictator or integration manager. @@ -594,7 +611,7 @@ If you received the patch from someone who generated it with the `git diff` or a This modifies the files in your working directory. It’s almost identical to running a `patch -p1` command to apply the patch, although it’s more paranoid and accepts fewer fuzzy matches than patch. It also handles file adds, deletes, and renames if they’re described in the `git diff` format, which `patch` won’t do. Finally, `git apply` is an "apply all or abort all" model where either everything is applied or nothing is, whereas `patch` can partially apply patchfiles, leaving your working directory in a weird state. `git apply` is overall much more paranoid than `patch`. It won’t create a commit for you — after running it, you must stage and commit the changes introduced manually. -You can also use git apply to see if a patch applies cleanly before you try actually applying it — you can run `git apply --check` with the patch: +You can also use `git apply` to see if a patch applies cleanly before you try actually applying it — you can run `git apply --check` with the patch: $ git apply --check 0001-seeing-if-this-helps-the-gem.patch error: patch failed: ticgit.gemspec:1 @@ -615,7 +632,7 @@ To apply a patch generated by `format-patch`, you use `git am`. Technically, `gi Limit log functionality to the first 20 -This is the beginning of the output of the format-patch command that you saw in the previous section. This is also a valid mbox e-mail format. If someone has e-mailed you the patch properly using git send-email, and you download that into an mbox format, then you can point git am to that mbox file, and it will start applying all the patches it sees. If you run a mail client that can save several e-mails out in mbox format, you can save entire patch series into a file and then use git am to apply them one at a time. +This is the beginning of the output of the format-patch command that you saw in the previous section. This is also a valid mbox e-mail format. If someone has e-mailed you the patch properly using `git send-email`, and you download that into an mbox format, then you can point `git am` to that mbox file, and it will start applying all the patches it sees. If you run a mail client that can save several e-mails out in mbox format, you can save entire patch series into a file and then use `git am` to apply them one at a time. However, if someone uploaded a patch file generated via `format-patch` to a ticketing system or something similar, you can save the file locally and then pass that file saved on your disk to `git am` to apply it: diff --git a/en/06-git-tools/01-chapter6.markdown b/en/06-git-tools/01-chapter6.markdown index 3eef10757..286ee7237 100644 --- a/en/06-git-tools/01-chapter6.markdown +++ b/en/06-git-tools/01-chapter6.markdown @@ -59,7 +59,7 @@ A lot of people become concerned at some point that they will, by random happens If you do happen to commit an object that hashes to the same SHA-1 value as a previous object in your repository, Git will see the previous object already in your Git database and assume it was already written. If you try to check out that object again at some point, you’ll always get the data of the first object. -However, you should be aware of how ridiculously unlikely this scenario is. The SHA-1 digest is 20 bytes or 160 bits. The number of randomly hashed objects needed to ensure a 50% probability of a single collision is about 2^80 (the formula for determining collision probability is `p = (n(n-1)/2) * (1/2^160))`. 2^80 is 1.2 x 10^24 or 1 million billion billion. That’s 1,200 times the number of grains of sand on the earth. +However, you should be aware of how ridiculously unlikely this scenario is. The SHA-1 digest is 20 bytes or 160 bits. The number of randomly hashed objects needed to ensure a 50% probability of a single collision is about 2^80 (the formula for determining collision probability is `p = (n(n-1)/2) * (1/2^160)`). 2^80 is 1.2 x 10^24 or 1 million billion billion. That’s 1,200 times the number of grains of sand on the earth. Here’s an example to give you an idea of what it would take to get a SHA-1 collision. If all 6.5 billion humans on Earth were programming, and every second, each one was producing code that was the equivalent of the entire Linux kernel history (1 million Git objects) and pushing it into one enormous Git repository, it would take 5 years until that repository contained enough objects to have a 50% probability of a single SHA-1 object collision. A higher probability exists that every member of your programming team will be attacked and killed by wolves in unrelated incidents on the same night. @@ -82,13 +82,13 @@ One of the things Git does in the background while you’re working away is keep You can see your reflog by using `git reflog`: $ git reflog - 734713b... HEAD@{0}: commit: fixed refs handling, added gc auto, updated - d921970... HEAD@{1}: merge phedders/rdocs: Merge made by recursive. - 1c002dd... HEAD@{2}: commit: added some blame and merge stuff - 1c36188... HEAD@{3}: rebase -i (squash): updating HEAD - 95df984... HEAD@{4}: commit: # This is a combination of two commits. - 1c36188... HEAD@{5}: rebase -i (squash): updating HEAD - 7e05da5... HEAD@{6}: rebase -i (pick): updating HEAD + 734713b HEAD@{0}: commit: fixed refs handling, added gc auto, updated + d921970 HEAD@{1}: merge phedders/rdocs: Merge made by recursive. + 1c002dd HEAD@{2}: commit: added some blame and merge stuff + 1c36188 HEAD@{3}: rebase -i (squash): updating HEAD + 95df984 HEAD@{4}: commit: # This is a combination of two commits. + 1c36188 HEAD@{5}: rebase -i (squash): updating HEAD + 7e05da5 HEAD@{6}: rebase -i (pick): updating HEAD Every time your branch tip is updated for any reason, Git stores that information for you in this temporary history. And you can specify older commits with this data, as well. If you want to see the fifth prior value of the HEAD of your repository, you can use the `@{n}` reference that you see in the reflog output: @@ -440,14 +440,14 @@ Your working directory is clean: $ git status # On branch master - nothing to commit (working directory clean) + nothing to commit, working directory clean At this point, you can easily switch branches and do work elsewhere; your changes are stored on your stack. To see which stashes you’ve stored, you can use `git stash list`: $ git stash list stash@{0}: WIP on master: 049d078 added the index file - stash@{1}: WIP on master: c264051... Revert "added file_size" - stash@{2}: WIP on master: 21d80a5... added number to log + stash@{1}: WIP on master: c264051 Revert "added file_size" + stash@{2}: WIP on master: 21d80a5 added number to log In this case, two stashes were done previously, so you have access to three different stashed works. You can reapply the one you just stashed by using the command shown in the help output of the original stash command: `git stash apply`. If you want to apply one of the older stashes, you can specify it by naming it, like this: `git stash apply stash@{2}`. If you don’t specify a stash, Git assumes the most recent stash and tries to apply it: @@ -481,8 +481,8 @@ The apply option only tries to apply the stashed work — you continue to have i $ git stash list stash@{0}: WIP on master: 049d078 added the index file - stash@{1}: WIP on master: c264051... Revert "added file_size" - stash@{2}: WIP on master: 21d80a5... added number to log + stash@{1}: WIP on master: c264051 Revert "added file_size" + stash@{2}: WIP on master: 21d80a5 added number to log $ git stash drop stash@{0} Dropped stash@{0} (364e91f3f268f0900bc3ee613f9f733e82aaed43) @@ -498,10 +498,10 @@ Again, if you don’t specify a stash, Git assumes the most recent stash: $ git stash show -p | git apply -R -You may want to create an alias and effectively add a `stash-unapply` command to your git. For example: +You may want to create an alias and effectively add a `stash-unapply` command to your Git. For example: $ git config --global alias.stash-unapply '!git stash show -p | git apply -R' - $ git stash + $ git stash apply $ #... work work work $ git stash-unapply @@ -566,12 +566,19 @@ Running this command gives you a list of commits in your text editor that looks # # Commands: # p, pick = use commit + # r, reword = use commit, but edit the commit message # e, edit = use commit, but stop for amending # s, squash = use commit, but meld into previous commit + # f, fixup = like "squash", but discard this commit's log message + # x, exec = run command (the rest of the line) using shell + # + # These lines can be re-ordered; they are executed from top to bottom. # # If you remove a line here THAT COMMIT WILL BE LOST. + # # However, if you remove everything, the rebase will be aborted. # + # Note that empty commits are commented out It’s important to note that these commits are listed in the opposite order than you normally see them using the `log` command. If you run a `log`, you see something like this: @@ -590,6 +597,10 @@ You need to edit the script so that it stops at the commit you want to edit. To When you save and exit the editor, Git rewinds you back to the last commit in that list and drops you on the command line with the following message: + + $ git rebase -i HEAD~3 Stopped at 7482e0d... updated the gemspec to hopefully work better You can amend the commit now, with @@ -632,12 +643,19 @@ It’s also possible to take a series of commits and squash them down into a sin # # Commands: # p, pick = use commit + # r, reword = use commit, but edit the commit message # e, edit = use commit, but stop for amending # s, squash = use commit, but meld into previous commit + # f, fixup = like "squash", but discard this commit's log message + # x, exec = run command (the rest of the line) using shell + # + # These lines can be re-ordered; they are executed from top to bottom. # # If you remove a line here THAT COMMIT WILL BE LOST. + # # However, if you remove everything, the rebase will be aborted. # + # Note that empty commits are commented out If, instead of "pick" or "edit", you specify "squash", Git applies both that change and the change directly before it and makes you merge the commit messages together. So, if you want to make a single commit from these three commits, you make the script look like this: @@ -690,7 +708,7 @@ Once again, this changes the SHAs of all the commits in your list, so make sure ### The Nuclear Option: filter-branch ### -There is another history-rewriting option that you can use if you need to rewrite a larger number of commits in some scriptable way — for instance, changing your e-mail address globally or removing a file from every commit. The command is `filter-branch`, and it can rewrite huge swaths of your history, so you probably shouldn’t use it unless your project isn’t yet public and other people haven’t based work off the commits you’re about to rewrite. However, it can be very useful. You’ll learn a few of the common uses so you can get an idea of some of the things it’s capable of. +There is another history-rewriting option that you can use if you need to rewrite a larger number of commits in some scriptable way — for instance, changing your e-mail address globally or removing a file from every commit. The command is `filter-branch`, and it can rewrite huge swaths of your history, so you probably shouldn’t use it unless your project isn’t yet public and other people haven’t based work off the commits you’re about to rewrite. However, it can be very useful. You’ll learn a few of the common uses so you can get an idea of some of the things it’s capable of. #### Removing a File from Every Commit #### @@ -730,6 +748,12 @@ Another common case is that you forgot to run `git config` to set your name and This goes through and rewrites every commit to have your new address. Because commits contain the SHA-1 values of their parents, this command changes every commit SHA in your history, not just those that have the matching e-mail address. +### The Very Fast Nuclear Option: Big Friendly Giant Repo Cleaner (BFG) ### + +[Roberto Tyley](https://github.com/rtyley) has written a similar tool to `filter-branch` called the BFG. BFG cannot do as much as `filter-branch`, but it is _very_ fast and on a large repository this can make a big difference. If the change you want to make is in the scope of BFG capability, and you have performance issues, then you should consider using it. + +See the [BFG](http://rtyley.github.io/bfg-repo-cleaner/) website for details. + ## Debugging with Git ## Git also provides a couple of tools to help you debug issues in your projects. Because Git is designed to work with nearly any type of project, these tools are pretty generic, but they can often help you hunt for a bug or culprit when things go wrong. @@ -1095,7 +1119,7 @@ Now you have the root of the Rack project in your `rack_branch` branch and your $ ls README -You want to pull the Rack project into your `master` project as a subdirectory. You can do that in Git with `git read-tree`. You’ll learn more about `read-tree` and its friends in Chapter 9, but for now know that it reads the root tree of one branch into your current staging area and working directory. You just switched back to your `master` branch, and you pull the `rack` branch into the `rack` subdirectory of your `master` branch of your main project: +You want to pull the Rack project into your `master` project as a subdirectory. You can do that in Git with `git read-tree`. You’ll learn more about `read-tree` and its friends in Chapter 9, but for now know that it reads the root tree of one branch into your current staging area and working directory. You just switched back to your `master` branch, and you pull the `rack_branch` branch into the `rack` subdirectory of your `master` branch of your main project: $ git read-tree --prefix=rack/ -u rack_branch diff --git a/en/07-customizing-git/01-chapter7.markdown b/en/07-customizing-git/01-chapter7.markdown index 7029378e5..d84e2629d 100644 --- a/en/07-customizing-git/01-chapter7.markdown +++ b/en/07-customizing-git/01-chapter7.markdown @@ -4,7 +4,7 @@ So far, I’ve covered the basics of how Git works and how to use it, and I’ve ## Git Configuration ## -As you briefly saw in the Chapter 1, you can specify Git configuration settings with the `git config` command. One of the first things you did was set up your name and e-mail address: +As you briefly saw in Chapter 1, you can specify Git configuration settings with the `git config` command. One of the first things you did was set up your name and e-mail address: $ git config --global user.name "John Doe" $ git config --global user.email johndoe@example.com @@ -130,7 +130,7 @@ In addition, each of these has subsettings you can use to set specific colors fo $ git config --global color.diff.meta "blue black bold" -You can set the color to any of the following values: normal, black, red, green, yellow, blue, magenta, cyan, or white. If you want an attribute like bold in the previous example, you can choose from bold, dim, ul, blink, and reverse. +You can set the color to any of the following values: `normal`, `black`, `red`, `green`, `yellow`, `blue`, `magenta`, `cyan`, or `white`, or, if your terminal supports more than 16 colors, an arbitrary numeric color value (between 0 and 255 on a 256-color terminal). If you want an attribute like bold in the previous example, you can choose from `bold`, `dim`, `ul`, `blink`, and `reverse`. See the `git config` manpage for all the subsettings you can configure, if you want to do that. @@ -142,7 +142,7 @@ If you want to try this out, P4Merge works on all major platforms, so you should You can download P4Merge here: - http://www.perforce.com/perforce/downloads/component.html + http://www.perforce.com/product/components/perforce-visual-merge-and-diff-tools To begin, you’ll set up external wrapper scripts to run your commands. I’ll use the Mac path for the executable; in other systems, it will be where your `p4merge` binary is installed. Set up a merge wrapper script named `extMerge` that calls your binary with all the arguments provided: @@ -511,7 +511,7 @@ For example, say you have some test files in a `test/` subdirectory, and it does test/ export-ignore -Now, when you run git archive to create a tarball of your project, that directory won’t be included in the archive. +Now, when you run `git archive` to create a tarball of your project, that directory won’t be included in the archive. #### export-subst #### @@ -535,6 +535,10 @@ This is helpful if a branch in your project has diverged or is specialized, but database.xml merge=ours +And then define a dummy `ours` merge strategy with: + + git config --global merge.ours.driver true + If you merge in the other branch, instead of having merge conflicts with the database.xml file, you see something like this: $ git merge topic @@ -613,14 +617,12 @@ All the server-side work will go into the update file in your hooks directory. T #!/usr/bin/env ruby - $refname = ARGV[0] - $oldrev = ARGV[1] - $newrev = ARGV[2] - $user = ENV['USER'] - - puts "Enforcing Policies... \n(#{$refname}) (#{$oldrev[0,6]}) (#{$newrev[0,6]})" + refname = ARGV[0] + oldrev = ARGV[1] + newrev = ARGV[2] + user = ENV['USER'] -Yes, I’m using global variables. Don’t judge me — it’s easier to demonstrate in this manner. + puts "Enforcing Policies... \n(#{refname}) (#{oldrev[0,6]}) (#{newrev[0,6]})" #### Enforcing a Specific Commit-Message Format #### diff --git a/en/08-git-and-other-scms/01-chapter8.markdown b/en/08-git-and-other-scms/01-chapter8.markdown index 7fddeda69..dfaa5e79c 100644 --- a/en/08-git-and-other-scms/01-chapter8.markdown +++ b/en/08-git-and-other-scms/01-chapter8.markdown @@ -202,7 +202,7 @@ Running `git svn rebase` every once in a while makes sure your code is always up ### Git Branching Issues ### -When you’ve become comfortable with a Git workflow, you’ll likely create topic branches, do work on them, and then merge them in. If you’re pushing to a Subversion server via git svn, you may want to rebase your work onto a single branch each time instead of merging branches together. The reason to prefer rebasing is that Subversion has a linear history and doesn’t deal with merges like Git does, so git svn follows only the first parent when converting the snapshots into Subversion commits. +When you’ve become comfortable with a Git workflow, you’ll likely create topic branches, do work on them, and then merge them in. If you’re pushing to a Subversion server via `git svn`, you may want to rebase your work onto a single branch each time instead of merging branches together. The reason to prefer rebasing is that Subversion has a linear history and doesn’t deal with merges like Git does, so `git svn` follows only the first parent when converting the snapshots into Subversion commits. Suppose your history looks like the following: you created an `experiment` branch, did two commits, and then merged them back into `master`. When you `dcommit`, you see output like this: @@ -231,7 +231,7 @@ When someone else clones that work, all they see is the merge commit with all th ### Subversion Branching ### -Branching in Subversion isn’t the same as branching in Git; if you can avoid using it much, that’s probably best. However, you can create and commit to branches in Subversion using git svn. +Branching in Subversion isn’t the same as branching in Git; if you can avoid using it much, that’s probably best. However, you can create and commit to branches in Subversion using `git svn`. #### Creating a New SVN Branch #### @@ -324,6 +324,17 @@ You can also get the same sort of information that `svn info` gives you by runni This is like `blame` and `log` in that it runs offline and is up to date only as of the last time you communicated with the Subversion server. +Tip: If your build scripts expect to be able to run `svn info` then providing a wrapper around git will often work. +Here is example to experiment with + + #!/usr/bin/env bash + + if git rev-parse --git-dir > /dev/null 2>&1 && [[ $1 == "info" ]] ; then + git svn info + else + /usr/local/bin/svn "$@" + fi + #### Ignoring What Subversion Ignores #### If you clone a Subversion repository that has `svn:ignore` properties set anywhere, you’ll likely want to set corresponding `.gitignore` files so you don’t accidentally commit files that you shouldn’t. `git svn` has two commands to help with this issue. The first is `git svn create-ignore`, which automatically creates corresponding `.gitignore` files for you so your next commit can include them. @@ -499,7 +510,7 @@ To quickly demonstrate, you’ll write a simple importer. Suppose you work in cu In order to import a Git directory, you need to review how Git stores its data. As you may remember, Git is fundamentally a linked list of commit objects that point to a snapshot of content. All you have to do is tell `fast-import` what the content snapshots are, what commit data points to them, and the order they go in. Your strategy will be to go through the snapshots one at a time and create commits with the contents of each directory, linking each commit back to the previous one. -As you did in the "An Example Git Enforced Policy" section of Chapter 7, we’ll write this in Ruby, because it’s what I generally work with and it tends to be easy to read. You can write this example pretty easily in anything you’re familiar with — it just needs to print the appropriate information to stdout. And, if you are running on Windows, this means you’ll need to take special care to not introduce carriage returns at the end your lines — git fast-import is very particular about just wanting line feeds (LF) not the carriage return line feeds (CRLF) that Windows uses. +As you did in the "An Example Git Enforced Policy" section of Chapter 7, we’ll write this in Ruby, because it’s what I generally work with and it tends to be easy to read. You can write this example pretty easily in anything you’re familiar with — it just needs to print the appropriate information to stdout. And, if you are running on Windows, this means you’ll need to take special care to not introduce carriage returns at the end your lines — `git fast-import` is very particular about just wanting line feeds (LF) not the carriage return line feeds (CRLF) that Windows uses. To begin, you’ll change into the target directory and identify every subdirectory, each of which is a snapshot that you want to import as a commit. You’ll change into each subdirectory and print the commands necessary to export it. Your basic main loop looks like this: @@ -601,7 +612,7 @@ The last thing you need to do is to return the current mark so it can be passed return mark -NOTE: If you are running on Windows you’ll need to make sure that you add one extra step. As metioned before, Windows uses CRLF for new line characters while git fast-import expects only LF. To get around this problem and make git fast-import happy, you need to tell ruby to use LF instead of CRLF: +NOTE: If you are running on Windows you’ll need to make sure that you add one extra step. As mentioned before, Windows uses CRLF for new line characters while `git fast-import` expects only LF. To get around this problem and make `git fast-import` happy, you need to tell ruby to use LF instead of CRLF: $stdout.binmode diff --git a/en/09-git-internals/01-chapter9.markdown b/en/09-git-internals/01-chapter9.markdown index 125d8524f..c64266683 100644 --- a/en/09-git-internals/01-chapter9.markdown +++ b/en/09-git-internals/01-chapter9.markdown @@ -27,7 +27,7 @@ When you run `git init` in a new or existing directory, Git creates the `.git` d objects/ refs/ -You may see some other files in there, but this is a fresh `git init` repository — it’s what you see by default. The `branches` directory isn’t used by newer Git versions, and the `description` file is only used by the GitWeb program, so don’t worry about those. The `config` file contains your project-specific configuration options, and the `info` directory keeps a global exclude file for ignored patterns that you don’t want to track in a .gitignore file. The `hooks` directory contains your client- or server-side hook scripts, which are discussed in detail in Chapter 7. +You may see some other files in there, but this is a fresh `git init` repository — it’s what you see by default. The `branches` directory isn’t used by newer Git versions, and the `description` file is only used by the GitWeb program, so don’t worry about those. The `config` file contains your project-specific configuration options, and the `info` directory keeps a global exclude file for ignored patterns that you don’t want to track in a `.gitignore` file. The `hooks` directory contains your client- or server-side hook scripts, which are discussed in detail in Chapter 7. This leaves four important entries: the `HEAD` and `index` files and the `objects` and `refs` directories. These are the core parts of Git. The `objects` directory stores all the content for your database, the `refs` directory stores pointers into commit objects in that data (branches), the `HEAD` file points to the branch you currently have checked out, and the `index` file is where Git stores your staging area information. You’ll now look at each of these sections in detail to see how Git operates. @@ -331,6 +331,12 @@ Figure 9-4. Git directory objects with branch head references included. When you run commands like `git branch (branchname)`, Git basically runs that `update-ref` command to add the SHA-1 of the last commit of the branch you’re on into whatever new reference you want to create. +If a reference is not found under the `refs` directory, Git then searches for it in the `.git/packed-refs` file, which contains space separated SHA-1 path pairs, for example: + + 52d771167707552d8e2a50f602c669e2ad135722 refs/tags/v1.0.1 + +This file exists for performance reasons, as it is more efficient to have a single file rather than many small ones for references that don't change very often. You can tell Git to pack references into that file by using the `git pack-refs` command. + ### The HEAD ### The question now is, when you run `git branch (branchname)`, how does Git know the SHA-1 of the last commit? The answer is the HEAD file. The HEAD file is a symbolic reference to the branch you’re currently on. By symbolic reference, I mean that unlike a normal reference, it doesn’t generally contain a SHA-1 value but rather a pointer to another reference. If you look at the file, you’ll normally see something like this: @@ -433,7 +439,7 @@ Let’s go back to the objects database for your test Git repository. At this po Git compresses the contents of these files with zlib, and you’re not storing much, so all these files collectively take up only 925 bytes. You’ll add some larger content to the repository to demonstrate an interesting feature of Git. Add the repo.rb file from the Grit library you worked with earlier — this is about a 12K source code file: - $ curl https://raw.github.com/mojombo/grit/master/lib/grit/repo.rb > repo.rb + $ curl -L https://raw.github.com/mojombo/grit/master/lib/grit/repo.rb > repo.rb $ git add repo.rb $ git commit -m 'added repo.rb' [master 484a592] added repo.rb @@ -456,7 +462,7 @@ You can then check how big is that object on your disk: Now, modify that file a little, and see what happens: - $ echo '# testing' >> repo.rb + $ echo '# testing' >> repo.rb $ git commit -am 'modified repo a bit' [master ab1afef] modified repo a bit 1 files changed, 1 insertions(+), 0 deletions(-) @@ -712,7 +718,7 @@ For example, say you run `git push origin master` in your project, and `origin` The `git-receive-pack` command immediately responds with one line for each reference it currently has — in this case, just the `master` branch and its SHA. The first line also has a list of the server’s capabilities (here, `report-status` and `delete-refs`). -Each line starts with a 4-byte hex value specifying how long the rest of the line is. Your first line starts with 005b, which is 91 in hex, meaning that 91 bytes remain on that line. The next line starts with 003e, which is 62, so you read the remaining 62 bytes. The next line is 0000, meaning the server is done with its references listing. +Each line starts with a 4-byte hex value specifying how long the rest of the line is. Your first line starts with 005b, which is 91 in decimal, meaning that 91 bytes remain on that line. The next line starts with 003e, which is 62, so you read the remaining 62 bytes. The next line is 0000, meaning the server is done with its references listing. Now that it knows the server’s state, your `send-pack` process determines what commits it has that the server doesn’t. For each reference that this push will update, the `send-pack` process tells the `receive-pack` process that information. For instance, if you’re updating the `master` branch and adding an `experiment` branch, the `send-pack` response may look something like this: diff --git a/eo/01-introduction/01-chapter1.markdown b/eo/01-introduction/01-chapter1.markdown index 9911a776b..2702db772 100644 --- a/eo/01-introduction/01-chapter1.markdown +++ b/eo/01-introduction/01-chapter1.markdown @@ -39,19 +39,19 @@ Figure 1-3. Distributed version control diagram. Furthermore, many of these systems deal pretty well with having several remote repositories they can work with, so you can collaborate with different groups of people in different ways simultaneously within the same project. This allows you to set up several types of workflows that aren’t possible in centralized systems, such as hierarchical models. -## A Short History of Git ## +## Mallonga historio de Git ## -As with many great things in life, Git began with a bit of creative destruction and fiery controversy. The Linux kernel is an open source software project of fairly large scope. For most of the lifetime of the Linux kernel maintenance (1991–2002), changes to the software were passed around as patches and archived files. In 2002, the Linux kernel project began using a proprietary DVCS system called BitKeeper. +Kiel pluraj el la bonaĵoj en la vivo, Git komenciĝis per iom da kreiga detruo kaj granda disputego. La Linux-kerno estas malfermitkoda programaro-projekto kun sufiĉe granda amplekso. Dum la plejparto de la tempo en kiu la Linux-kerno estis prizorgata (1991–2002), oni disdonis ŝanĝojn al la programaro kiel flikaĵoj kaj enarkivigitaj dosieroj. En 2002, la Linux-kerna projekto komencis uzi proprietan DVCS-sistemon nomita BitKeeper. -In 2005, the relationship between the community that developed the Linux kernel and the commercial company that developed BitKeeper broke down, and the tool’s free-of-charge status was revoked. This prompted the Linux development community (and in particular Linus Torvalds, the creator of Linux) to develop their own tool based on some of the lessons they learned while using BitKeeper. Some of the goals of the new system were as follows: +En 2005 rompiĝis la rilato inter la komunumo, en kiu la Linux-kerno evoluis, kaj la komerco firmao, kiu produktis BitKeeper; oni senvalidigis la senkostan statuson de la ilo. Tio instigis la komunumo, kiu sin prizorgis pri la evoluo de Linux—kaj precipe Linus Torvalds, la kreinto de Linux—krei sian propran ilon, tenante en la menso la lecionojn, kiujn ili lernis, dum ili uzis BitKeeper. Jen kelkaj el la celoj de la nova sistemo: -* Speed -* Simple design -* Strong support for non-linear development (thousands of parallel branches) -* Fully distributed -* Able to handle large projects like the Linux kernel efficiently (speed and data size) +* Rapideco +* Simpla desegno +* Bona subteno por nelinea konstruado (miloj da paralelaj branĉoj) +* Tute disa sistemo +* La ebleco rendimente trakti grandajn projektojn (kiel la Linux-kerno) koncerne al rapideco kaj datuma grandeco -Since its birth in 2005, Git has evolved and matured to be easy to use and yet retain these initial qualities. It’s incredibly fast, it’s very efficient with large projects, and it has an incredible branching system for non-linear development (See Chapter 3). +Ekde ĝia naskiĝo en 2005, Git evoluis kaj prenkreskiĝis por esti facile uzebla kaj tamen reteni tiujn dekomencaj ecoj. Ĝi estas nekredeble rapida; ĝi estas tre rendimenta kun grandaj projektoj; kaj ĝi havas bonegan branĉigan sistemon por nelinea konstruado (vidu Ĉapitro 3). ## Git Basics ## @@ -161,9 +161,9 @@ Or if you’re on a Debian-based distribution like Ubuntu, try apt-get: ### Installing on Mac ### -There are two easy ways to install Git on a Mac. The easiest is to use the graphical Git installer, which you can download from the Google Code page (see Figure 1-7): +There are two easy ways to install Git on a Mac. The easiest is to use the graphical Git installer, which you can download from the SourceForge page (see Figure 1-7): - http://code.google.com/p/git-osx-installer + http://sourceforge.net/projects/git-osx-installer/ Insert 18333fig0107.png Figure 1-7. Git OS X installer. diff --git a/eo/02-git-basics/01-chapter2.markdown b/eo/02-git-basics/01-chapter2.markdown index be6a22bcf..78f6820c2 100644 --- a/eo/02-git-basics/01-chapter2.markdown +++ b/eo/02-git-basics/01-chapter2.markdown @@ -55,7 +55,7 @@ The main tool you use to determine which files are in which state is the `git st $ git status # On branch master - nothing to commit (working directory clean) + nothing to commit, working directory clean This means you have a clean working directory — in other words, no tracked files are modified. Git also doesn’t see any untracked files, or they would be listed here. Finally, the command tells you which branch you’re on. For now, that is always `master`, which is the default; you won’t worry about it here. The next chapter will go over branches and references in detail. diff --git a/es-ni/01-introduction/01-chapter1.markdown b/es-ni/01-introduction/01-chapter1.markdown index 36868fc48..7b8de3c69 100755 --- a/es-ni/01-introduction/01-chapter1.markdown +++ b/es-ni/01-introduction/01-chapter1.markdown @@ -161,9 +161,9 @@ Or if you’re on a Debian-based distribution like Ubuntu, try apt-get: ### Installing on Mac ### -There are two easy ways to install Git on a Mac. The easiest is to use the graphical Git installer, which you can download from the Google Code page (see Figure 1-7): +There are two easy ways to install Git on a Mac. The easiest is to use the graphical Git installer, which you can download from the SourceForge page (see Figure 1-7): - http://code.google.com/p/git-osx-installer + http://sourceforge.net/projects/git-osx-installer/ Insert 18333fig0107.png Figure 1-7. Git OS X installer diff --git a/es-ni/02-git-basics/01-chapter2.markdown b/es-ni/02-git-basics/01-chapter2.markdown index aac17c27c..701d8c983 100644 --- a/es-ni/02-git-basics/01-chapter2.markdown +++ b/es-ni/02-git-basics/01-chapter2.markdown @@ -55,7 +55,7 @@ La herramienta principal que se utiliza para determinar qué archivos están en $ git status # On branch master - nothing to commit (working directory clean) + nothing to commit, working directory clean Esto significa que tienes una copia de trabajo limpia, en otras palabras, que no hay ningún archivo versionado que haya sido modificado. Git tampoco detectó ningún archivo sin versionar, de otra manera debería estar listado aquí. Por último, el comando indica en qué branch estás trabajando. Por ahora, siempre será master, que es el branch por defecto; no hace falta que te preocupes por saber qué significa en este punto aún. En el próximo capítulo analizaremos los branches y referencias en detalle. diff --git a/es/01-introduction/01-chapter1.markdown b/es/01-introduction/01-chapter1.markdown index 0321144ba..692764e4c 100644 --- a/es/01-introduction/01-chapter1.markdown +++ b/es/01-introduction/01-chapter1.markdown @@ -4,7 +4,7 @@ Este capítulo tratará sobre cómo empezar con Git. Partiremos explicando algun ## Acerca del control de versiones ## -¿Qué es el control de versiones, y por qué debería importarte? El control de versiones es un sistema que registra los cambios realizados sobre un archivo o conjunto de archivos a lo largo del tiempo, de modo que puedas recuperar versiones específicas más adelante. Para los ejemplos de este libro llevarás control de versiones de código fuente, aunque en realidad puedes hacer esto con casi cualquier tipo de archivo que encuentres en un ordenador. +¿Qué es el control de versiones, y por qué debería importarte? El control de versiones es un sistema que registra los cambios realizados sobre un archivo o conjunto de archivos a lo largo del tiempo, de modo que puedas recuperar versiones específicas más adelante. A pesar de que los ejemplos de este libro muestran código fuente como archivos bajo control de versiones, en realidad cualquier tipo de archivo que encuentres en un ordenador puede ponerse bajo control de versiones. Si eres diseñador gráfico o web, y quieres mantener cada versión de una imagen o diseño (algo que sin duda quieres), un sistema de control de versiones (Version Control System o VCS en inglés) es una elección muy sabia. Te permite revertir archivos a un estado anterior, revertir el proyecto entero a un estado anterior, comparar cambios a lo largo del tiempo, ver quién modificó por última vez algo que puede estar causando un problema, quién introdujo un error y cuándo, y mucho más. Usar un VCS también significa generalmente que si fastidias o pierdes archivos, puedes recuperarlos fácilmente. Además, obtienes todos estos beneficios a un coste muy bajo. @@ -87,13 +87,13 @@ El mecanismo que usa Git para generar esta suma de comprobación se conoce como 24b9da6552252987aa493b52f8696cd6d3b00373 -Verás estos valores hash por todos lados en Git, ya que los usa con mucha frecuencia. De hecho, Git no guarda todo por nombre de archivo, sino por el valor hash de sus contenidos. +Verás estos valores hash por todos lados en Git, ya que los usa con mucha frecuencia. De hecho, Git guarda todo no por nombre de archivo, sino por el valor hash de sus contenidos. ### Git generalmente sólo añade información ### Cuando realizas acciones en Git, casi todas ellas sólo añaden información a la base de datos de Git. Es muy difícil conseguir que el sistema haga algo que no se pueda deshacer, o que de algún modo borre información. Como en cualquier VCS, puedes perder o estropear cambios que no has confirmado todavía; pero después de confirmar una instantánea en Git, es muy difícil de perder, especialmente si envías (push) tu base de datos a otro repositorio con regularidad. -Esto hace que usar Git sea un placer, porque sabemos que podemos experimentar sin peligro de fastidiar gravemente las cosas. Para un análisis más exhaustivo de cómo almacena Git su información y cómo puedes recuperar datos aparentemente perdidos, ver “Entre bambalinas” en el Capítulo 9. +Esto hace que usar Git sea un placer, porque sabemos que podemos experimentar sin peligro de fastidiar gravemente las cosas. Para un análisis más exhaustivo de cómo almacena Git su información y cómo puedes recuperar datos aparentemente perdidos, ver Capítulo 9. ### Los tres estados ### @@ -102,7 +102,7 @@ Ahora presta atención. Esto es lo más importante a recordar acerca de Git si q Esto nos lleva a las tres secciones principales de un proyecto de Git: el directorio de Git (Git directory), el directorio de trabajo (working directory), y el área de preparación (staging area). Insert 18333fig0106.png -Figura 1-6. Directorio de trabajo, área de preparación, y directorio de Git. +Figura 1-6. Directorio de trabajo, área de preparación y directorio de Git. El directorio de Git es donde Git almacena los metadatos y la base de datos de objetos para tu proyecto. Es la parte más importante de Git, y es lo que se copia cuando clonas un repositorio desde otro ordenador. @@ -126,13 +126,13 @@ Vamos a empezar a usar un poco de Git. Lo primero es lo primero: tienes que inst Si puedes, en general es útil instalar Git desde código fuente, porque obtendrás la versión más reciente. Cada versión de Git tiende a incluir útiles mejoras en la interfaz de usuario, por lo que utilizar la última versión es a menudo el camino más adecuado si te sientes cómodo compilando software desde código fuente. También ocurre que muchas distribuciones de Linux contienen paquetes muy antiguos; así que a menos que estés en una distribución muy actualizada o estés usando backports, instalar desde código fuente puede ser la mejor opción. -Para instalar Git, necesitas tener las siguientes librerías de las que Git depende: curl, zlib, openssl, expat, y libiconv. Por ejemplo, si estás en un sistema que tiene yum (como Fedora) o apt-get (como un sistema basado en Debian), puedes usar estos comandos para instalar todas las dependencias: +Para instalar Git, necesitas tener las siguientes librerías de las que Git depende: curl, zlib, openssl, expat y libiconv. Por ejemplo, si estás en un sistema que tiene yum (como Fedora) o apt-get (como un sistema basado en Debian), puedes usar estos comandos para instalar todas las dependencias: $ yum install curl-devel expat-devel gettext-devel \ openssl-devel zlib-devel $ apt-get install libcurl4-gnutls-dev libexpat1-dev gettext \ - libz-dev + libz-dev libssl-dev Cuando tengas todas las dependencias necesarias, puedes descargar la versión más reciente de Git desde su página web: @@ -161,19 +161,23 @@ O si estás en una distribución basada en Debian como Ubuntu, prueba con apt-ge ### Instalando en Mac ### -Hay dos maneras fáciles de instalar Git en un Mac. La más sencilla es usar el instalador gráfico de Git, que puedes descargar desde la página de Google Code (véase Figura 1-7): +Hay tres maneras fáciles de instalar Git en un Mac. La más sencilla es usar el instalador gráfico de Git, que puedes descargar desde la página de SourceForge (véase Figura 1-7): - http://code.google.com/p/git-osx-installer + http://sourceforge.net/projects/git-osx-installer/ Insert 18333fig0107.png Figura 1-7. Instalador de Git para OS X. -La otra manera es instalar Git a través de MacPorts (`http://www.macports.org`). Si tienes MacPorts instalado, instala Git con: +Una alternativa es instalar Git a través de MacPorts (`http://www.macports.org`). Si tienes MacPorts instalado, instala Git con: $ sudo port install git-core +svn +doc +bash_completion +gitweb No necesitas añadir todos los extras, pero probablemente quieras incluir +svn en caso de que alguna vez necesites usar Git con repositorios Subversion (véase el Capítulo 8). +La segunda alternativa es Homebrew (`http://brew.sh/`). Si ya tienes instalado Homebrew, instala Git con: + + $ brew install git + ### Instalando en Windows ### Instalar Git en Windows es muy fácil. El proyecto msysGit tiene uno de los procesos de instalación más sencillos. Simplemente descarga el archivo exe del instalador desde la página de GitHub, y ejecútalo: @@ -182,6 +186,8 @@ Instalar Git en Windows es muy fácil. El proyecto msysGit tiene uno de los proc Una vez instalado, tendrás tanto la versión de línea de comandos (incluido un cliente SSH que nos será útil más adelante) como la interfaz gráfica de usuario estándar. +Nota para el uso en Windows: Se debería usar Git con la shell provista por msysGit (estilo Unix), lo cual permite usar las complejas líneas de comandos de este libro. Si por cualquier razón se necesitara usar la shell nativa de Windows, la consola de línea de comandos, se han de usar las comillas dobles en vez de las simples (para parámetros que contengan espacios) y se deben entrecomillar los parámetros terminándolos con el acento circunflejo (^) si están al final de la línea, ya que en Windows es uno de los símbolos de continuación. + ## Configurando Git por primera vez ## Ahora que tienes Git en tu sistema, querrás hacer algunas cosas para personalizar tu entorno de Git. Sólo es necesario hacer estas cosas una vez; se mantendrán entre actualizaciones. También puedes cambiarlas en cualquier momento volviendo a ejecutar los comandos correspondientes. @@ -190,9 +196,9 @@ Git trae una herramienta llamada `git config` que te permite obtener y establece * Archivo `/etc/gitconfig`: Contiene valores para todos los usuarios del sistema y todos sus repositorios. Si pasas la opción `--system` a `git config`, lee y escribe específicamente en este archivo. * Archivo `~/.gitconfig` file: Específico a tu usuario. Puedes hacer que Git lea y escriba específicamente en este archivo pasando la opción `--global`. -* Archivo config en el directorio de git (es decir, `.git/config`) del repositorio que estés utilizando actualmente: Específico a ese repositorio. Cada nivel sobrescribe los valores del nivel anterior, por lo que los valores de `.git/config` tienen preferencia sobre los de `/etc/gitconfig`. +* Archivo config en el directorio de Git (es decir, `.git/config`) del repositorio que estés utilizando actualmente: Específico a ese repositorio. Cada nivel sobrescribe los valores del nivel anterior, por lo que los valores de `.git/config` tienen preferencia sobre los de `/etc/gitconfig`. -En sistemas Windows, Git busca el archivo `.gitconfig` en el directorio `$HOME` (`C:\Documents and Settings\$USER` para la mayoría de usuarios). También busca en el directorio `/etc/gitconfig`, aunque esta ruta es relativa a la raíz MSys, que es donde quiera que decidieses instalar Git en tu sistema Windows cuando ejecutaste el instalador. +En sistemas Windows, Git busca el archivo `.gitconfig` en el directorio `$HOME` (`%USERPROFILE%` in Windows’ environment), que es `C:\Documents and Settings\$USER` para la mayoría de usuarios, dependiendo de la versión (`$USER` es `%USERNAME%` en el entorno Windows). También busca en el directorio `/etc/gitconfig`, aunque esta ruta es relativa a la raíz MSys, que es donde quiera que decidieses instalar Git en tu sistema Windows cuando ejecutaste el instalador. ### Tu identidad ### diff --git a/es/02-git-basics/01-chapter2.markdown b/es/02-git-basics/01-chapter2.markdown index 62196fc18..d4e8d4098 100644 --- a/es/02-git-basics/01-chapter2.markdown +++ b/es/02-git-basics/01-chapter2.markdown @@ -12,7 +12,7 @@ Si estás empezando el seguimiento en Git de un proyecto existente, necesitas ir $ git init -Esto crea un nuevo subdirectorio llamado .git que contiene todos los archivos necesarios del repositorio — un esqueleto de un repositorio Git. Todavía no hay nada en tu proyecto que esté bajo seguimiento. (Véase el Capítulo 9 para obtener más información sobre qué archivos están contenidos en el directorio `.git` que acabas de crear.) +Esto crea un nuevo subdirectorio llamado .git que contiene todos los archivos necesarios del repositorio —un esqueleto de un repositorio Git. Todavía no hay nada en tu proyecto que esté bajo seguimiento. (Véase el Capítulo 9 para obtener más información sobre qué archivos están contenidos en el directorio `.git` que acabas de crear.) Si deseas empezar a controlar versiones de archivos existentes (a diferencia de un directorio vacío), probablemente deberías comenzar el seguimiento de esos archivos y hacer una confirmación inicial. Puedes conseguirlo con unos pocos comandos `git add` para especificar qué archivos quieres controlar, seguidos de un `commit` para confirmar los cambios: @@ -55,7 +55,7 @@ Tu principal herramienta para determinar qué archivos están en qué estado es $ git status # On branch master - nothing to commit (working directory clean) + nothing to commit, working directory clean Esto significa que tienes un directorio de trabajo limpio —en otras palabras, no tienes archivos bajo seguimiento y modificados—. Git tampoco ve ningún archivo que no esté bajo seguimiento, o estaría listado ahí. Por último, el comando te dice en qué rama estás. Por ahora, esa rama siempre es "master", que es la predeterminada. No te preocupes de eso por ahora, el siguiente capítulo tratará los temas de las ramas y las referencias en detalle. @@ -165,7 +165,7 @@ Las reglas para los patrones que pueden ser incluidos en el archivo .gitignore s * Puedes indicar un directorio añadiendo una barra hacia delante (`/`) al final. * Puedes negar un patrón añadiendo una exclamación (`!`) al principio. -Los patrones glob son expresiones regulares simplificadas que pueden ser usadas por las shells. Un asterisco (`*`) reconoce cero o más caracteres; `[abc]` reconoce cualquier carácter de los especificados entre corchetes (en este caso, a, b, o c); una interrogación (`?`) reconoce un único carácter; y caracteres entre corchetes separados por un guión (`[0-9]`) reconoce cualquier carácter entre ellos (en este caso, de 0 a 9). +Los patrones glob son expresiones regulares simplificadas que pueden ser usadas por las shells. Un asterisco (`*`) reconoce cero o más caracteres; `[abc]` reconoce cualquier carácter de los especificados entre corchetes (en este caso, a, b o c); una interrogación (`?`) reconoce un único carácter; y caracteres entre corchetes separados por un guión (`[0-9]`) reconoce cualquier carácter entre ellos (en este caso, de 0 a 9). He aquí otro ejemplo de archivo .gitignore: @@ -180,10 +180,14 @@ He aquí otro ejemplo de archivo .gitignore: build/ # ignore doc/notes.txt, but not doc/server/arch.txt doc/*.txt + # ignore all .txt files in the doc/ directory + doc/**/*.txt + +El patrón `**/` está disponible en Git desde la versión 1.8.2. ### Viendo tus cambios preparados y no preparados ### -Si el comando `git status` es demasiado impreciso para ti —quieres saber exactamente lo que ha cambiado, no sólo qué archivos fueron modificados— puedes usar el comando `git diff`. Veremos `git diff` en más detalle después; pero probablemente lo usarás para responder estas dos preguntas: ¿qué has cambiado pero aún no has preparado?, y ¿qué has preparado y estás a punto de confirmar? Aunque `git status` responde esas preguntas de manera general, `git diff` te muestra exactamente las líneas añadidas y eliminadas —el parche, como si dijésemos—. +Si el comando `git status` es demasiado impreciso para ti —quieres saber exactamente lo que ha cambiado, no sólo qué archivos fueron modificados— puedes usar el comando `git diff`. Veremos `git diff` en más detalle después; pero probablemente lo usarás para responder estas dos preguntas: ¿qué has cambiado pero aún no has preparado?, y ¿qué has preparado y estás a punto de confirmar? Aunque `git status` responde esas preguntas de manera general, `git diff` te muestra exactamente las líneas añadidas y eliminadas —el parche, como si dijésemos. Supongamos que quieres editar y preparar el archivo README otra vez, y luego editar el archivo benchmarks.rb sin prepararlo. Si ejecutas el comando `status`, de nuevo verás algo así: @@ -380,7 +384,7 @@ El comando `git rm` acepta archivos, directorios, y patrones glob. Es decir, que $ git rm log/\*.log -Fíjate en la barra hacia atrás (`\`) antes del `*`. Es necesaria debido a que Git hace su propia expansión de rutas, además de la expansión que hace tu shell. Este comando elimina todos los archivos con la extensión `.log` en el directorio `log/`. También puedes hacer algo así: +Fíjate en la barra hacia atrás (`\`) antes del `*`. Es necesaria debido a que Git hace su propia expansión de rutas, además de la expansión que hace tu shell. En la consola del sistema de Windows, esta barra debe de ser omitida. Este comando elimina todos los archivos con la extensión `.log` en el directorio `log/`. También puedes hacer algo así: $ git rm \*~ @@ -388,7 +392,7 @@ Este comando elimina todos los archivos que terminan en `~`. ### Moviendo archivos ### -A diferencia de muchos otros VCSs, Git no hace un seguimiento explicito del movimiento de archivos. Si renombras un archivo, en Git no se almacena ningún metadato que indique que lo has renombrado. Sin embargo, Git es suficientemente inteligente como para darse cuenta —trataremos el tema de la detección de movimiento de archivos un poco más adelante—. +A diferencia de muchos otros VCSs, Git no hace un seguimiento explicito del movimiento de archivos. Si renombras un archivo, en Git no se almacena ningún metadato que indique que lo has renombrado. Sin embargo, Git es suficientemente inteligente como para darse cuenta —trataremos el tema de la detección de movimiento de archivos un poco más adelante. Por tanto, es un poco desconcertante que Git tenga un comando `mv`. Si quieres renombrar un archivo en Git, puedes ejecutar algo así: @@ -490,6 +494,26 @@ Una de las opciones más útiles es `-p`, que muestra las diferencias introducid Esta opción muestra la misma información, pero añadiendo tras cada entrada las diferencias que le corresponden. Esto resulta muy útil para revisiones de código, o para visualizar rápidamente lo que ha pasado en las confirmaciones enviadas por un colaborador. +A veces es más fácil revisar cambios a nivel de palabra que a nivel de línea. Git dispone de la opción `--word-diff`, que se puede añadir al comando `git log -p` para obtener las diferencias por palabras en lugar de las diferencias línea por línea. Formatear las diferencias a nivel de palabra es bastante inusual cuando se aplica a código fuente, pero resulta muy práctico cuando se aplica a grandes archivos de texto, como libros o tu propia tesis. He aquí un ejemplo: + + $ git log -U1 --word-diff + commit ca82a6dff817ec66f44342007202690a93763949 + Author: Scott Chacon + Date: Mon Mar 17 21:52:11 2008 -0700 + + changed the version number + + diff --git a/Rakefile b/Rakefile + index a874b73..8f94139 100644 + --- a/Rakefile + +++ b/Rakefile + @@ -7,3 +7,3 @@ spec = Gem::Specification.new do |s| + s.name = "simplegit" + s.version = [-"0.1.0"-]{+"0.1.1"+} + s.author = "Scott Chacon" + +Como se puede ver, no aparecen líneas añadidas o eliminadas en la salida como en las diferencias normales. Se puede ver la palabra añadida encerrada en `{+ +}` y la eliminada en `[- -]`. Puede que se quiera reducir las usuales tres líneas de contexto en las diferencias a sólo una línea puesto que el contexto es ahora de palabras, no de líneas. Se puede hacer esto con `-U1`, como hicimos en el ejemplo de arriba. + También puedes usar con `git log` una serie de opciones de resumen. Por ejemplo, si quieres ver algunas estadísticas de cada confirmación, puedes usar la opción `--stat`: $ git log --stat @@ -573,10 +597,11 @@ Las opciones `oneline` y `format` son especialmente útiles combinadas con otra * d6016bc require time for xmlschema * 11d191e Merge branch 'defunkt' into local -Éstas son sólo algunas de las opciones para formatear la salida de `git log` —existen muchas más. La Tabla 2-2 lista las opcines vistas hasta ahora, y algunas otras opciones de formateo que pueden resultarte útiles, así como su efecto sobre la salida—. +Éstas son sólo algunas de las opciones para formatear la salida de `git log` —existen muchas más. La Tabla 2-2 lista las opciones vistas hasta ahora, y algunas otras opciones de formateo que pueden resultarte útiles, así como su efecto sobre la salida. Opción Descripción -p Muestra el parche introducido en cada confirmación. + --word-diff Muestra el parche en formato de una palabra. --stat Muestra estadísticas sobre los archivos modificados en cada confirmación. --shortstat Muestra solamente la línea de resumen de la opción `--stat`. --name-only Muestra la lista de archivos afectados. @@ -584,7 +609,8 @@ Las opciones `oneline` y `format` son especialmente útiles combinadas con otra --abbrev-commit Muestra solamente los primeros caracteres de la suma SHA-1, en vez de los 40 caracteres de que se compone. --relative-date Muestra la fecha en formato relativo (por ejemplo, “2 weeks ago” (“hace 2 semanas”)) en lugar del formato completo. --graph Muestra un gráfico ASCII con la historia de ramificaciones y uniones. - --pretty Muestra las confirmaciones usando un formato alternativo. Posibles opciones son oneline, short, full, fuller, y format (mediante el cual puedes especificar tu propio formato). + --pretty Muestra las confirmaciones usando un formato alternativo. Posibles opciones son oneline, short, full, fuller y format (mediante el cual puedes especificar tu propio formato). + --oneline Un cómodo acortamiento de la opción `--pretty=oneline --abbrev-commit`. ### Limitando la salida del histórico ### @@ -598,6 +624,13 @@ Este comando acepta muchos formatos. Puedes indicar una fecha concreta (“2008- También puedes filtrar la lista para que muestre sólo aquellas confirmaciones que cumplen ciertos criterios. La opción `--author` te permite filtrar por autor, y `--grep` te permite buscar palabras clave entre los mensajes de confirmación. (Ten en cuenta que si quieres aplicar ambas opciones simultáneamente, tienes que añadir `--all-match`, o el comando mostrará las confirmaciones que cumplan cualquiera de las dos, no necesariamente las dos a la vez.) + + La última opción verdaderamente útil para filtrar la salida de `git log` es especificar una ruta. Si especificas la ruta de un directorio o archivo, puedes limitar la salida a aquellas confirmaciones que introdujeron un cambio en dichos archivos. Ésta debe ser siempre la última opción, y suele ir precedida de dos guiones (`--`) para separar la ruta del resto de opciones. En la Tabla 2-3 se listan estas opciones, y algunas otras bastante comunes, a modo de referencia. @@ -652,7 +685,7 @@ Por ejemplo, si confirmas y luego te das cuenta de que se te olvidó preparar lo $ git add forgotten_file $ git commit --amend -Estos tres comandos acabarán convirtiéndose en una única confirmación —la segunda confirmación reemplazará los resultados de la primera—. +Estos tres comandos acabarán convirtiéndose en una única confirmación —la segunda confirmación reemplazará los resultados de la primera. ### Deshaciendo la preparación de un archivo ### @@ -690,7 +723,7 @@ El comando es un poco extraño, pero funciona. El archivo benchmarks.rb ahora es ### Deshaciendo la modificación de un archivo ### -¿Qué pasa si te das cuenta de que no quieres mantener las modificaciones que has hecho sobre el archivo benchmarks.rb? ¿Cómo puedes deshacerlas fácilmente —revertir el archivo al mismo estado en el que estaba cuando hiciste tu última confirmación— (o cuando clonaste el repositorio, o como quiera que metieses el archivo en tu directorio de trabajo)? Afortunadamente, `git status` también te dice como hacer esto. En la salida del último ejemplo, la cosa estaba así: +¿Qué pasa si te das cuenta de que no quieres mantener las modificaciones que has hecho sobre el archivo benchmarks.rb? ¿Cómo puedes deshacerlas fácilmente —revertir el archivo al mismo estado en el que estaba cuando hiciste tu última confirmación (o cuando clonaste el repositorio, o como quiera que metieses el archivo en tu directorio de trabajo)? Afortunadamente, `git status` también te dice como hacer esto. En la salida del último ejemplo, la cosa estaba así: # Changes not staged for commit: # (use "git add ..." to update what will be committed) @@ -699,7 +732,7 @@ El comando es un poco extraño, pero funciona. El archivo benchmarks.rb ahora es # modified: benchmarks.rb # -Te dice de forma bastante explícita cómo descartar las modificaciones que hayas hecho (al menos las versiones de Git a partir de la 1.6.1 lo hacen —si tienes una versión más antigua, te recomendamos encarecidamente que la actualices para obtener algunas de estas mejoras de usabilidad—). Vamos a hacer lo que dice: +Te dice de forma bastante explícita cómo descartar las modificaciones que hayas hecho (al menos las versiones de Git a partir de la 1.6.1 lo hacen —si tienes una versión más antigua, te recomendamos encarecidamente que la actualices para obtener algunas de estas mejoras de usabilidad). Vamos a hacer lo que dice: $ git checkout -- benchmarks.rb $ git status @@ -738,7 +771,8 @@ Para ver qué repositorios remotos tienes configurados, puedes ejecutar el coman También puedes añadir la opción `-v`, que muestra la URL asociada a cada repositorio remoto: $ git remote -v - origin git://github.com/schacon/ticgit.git + origin git://github.com/schacon/ticgit.git (fetch) + origin git://github.com/schacon/ticgit.git (push) Si tienes más de un remoto, este comando los lista todos. Por ejemplo, mi repositorio Grit tiene esta pinta: @@ -774,7 +808,7 @@ Ahora puedes usar la cadena "pb" en la línea de comandos, en lugar de toda la U * [new branch] master -> pb/master * [new branch] ticgit -> pb/ticgit -La rama maestra de Paul es accesible localmente como `pb/master` —puedes unirla a una de tus ramas, o copiarla localmente para inspeccionarla—. +La rama maestra de Paul es accesible localmente como `pb/master` —puedes unirla a una de tus ramas, o copiarla localmente para inspeccionarla. ### Recibiendo de tus repositorios remotos ### @@ -784,7 +818,7 @@ Como acabas de ver, para recuperar datos de tus repositorios remotos puedes ejec Este comando recupera todos los datos del proyecto remoto que no tengas todavía. Después de hacer esto, deberías tener referencias a todas las ramas del repositorio remoto, que puedes unir o inspeccionar en cualquier momento. (Veremos qué son las ramas y cómo utilizarlas en más detalle en el Capítulo 3.) -Si clonas un repositorio, el comando añade automáticamente ese repositorio remoto con el nombre de "origin". Por tanto, `git fetch origin` recupera toda la información enviada a ese servidor desde que lo clonaste (o desde la última vez que ejecutaste `fetch`). Es importante tener en cuenta que el comando `fetch` sólo recupera la información y la pone en tu repositorio local —no la une automáticamente con tu trabajo ni modifica aquello en lo que estás trabajando. Tendrás que unir ambos manualmente a posteriori—. +Si clonas un repositorio, el comando añade automáticamente ese repositorio remoto con el nombre de "origin". Por tanto, `git fetch origin` recupera toda la información enviada a ese servidor desde que lo clonaste (o desde la última vez que ejecutaste `fetch`). Es importante tener en cuenta que el comando `fetch` sólo recupera la información y la pone en tu repositorio local —no la une automáticamente con tu trabajo ni modifica aquello en lo que estás trabajando. Tendrás que unir ambos manualmente a posteriori. Si has configurado una rama para seguir otra rama remota (véase la siguiente sección y el Capítulo 3 para más información), puedes usar el comando `git pull` para recuperar y unir automáticamente la rama remota con tu rama actual. Éste puede resultarte un flujo de trabajo más sencillo y más cómodo; y por defecto, el comando `git clone` automáticamente configura tu rama local maestra para que siga la rama remota maestra del servidor del cual clonaste (asumiendo que el repositorio remoto tiene una rama maestra). Al ejecutar `git pull`, por lo general se recupera la información del servidor del que clonaste, y automáticamente se intenta unir con el código con el que estás trabajando actualmente. @@ -856,7 +890,7 @@ Si por algún motivo quieres eliminar una referencia —has movido el servidor o ## Creando etiquetas ## -Como muchos VCSs, Git tiene la habilidad de etiquetar (tag) puntos específicos en la historia como importantes. Generalmente la gente usa esta funcionalidad para marcar puntos donde se ha lanzado alguna versión (v1.0, y así sucesivamente). En esta sección aprenderás cómo listar las etiquetas disponibles, crear nuevas etiquetas y qué tipos diferentes de etiquetas hay- +Como muchos VCSs, Git tiene la habilidad de etiquetar (tag) puntos específicos en la historia como importantes. Generalmente la gente usa esta funcionalidad para marcar puntos donde se ha lanzado alguna versión (v1.0, y así sucesivamente). En esta sección aprenderás cómo listar las etiquetas disponibles, crear nuevas etiquetas y qué tipos diferentes de etiquetas hay. ### Listando tus etiquetas ### @@ -868,7 +902,7 @@ Listar las etiquetas disponibles en Git es sencillo, Simplemente escribe `git ta Este comando lista las etiquetas en orden alfabético; el orden en el que aparecen no es realmente importante. -También puedes buscar etiquetas de acuerdo a un patrón en particular. El repositorio fuente de Git, por ejemplo, contiene mas de 240 etiquetas. Si solo estas interesado en la serie 1.4.2, puedes ejecutar esto: +También puedes buscar etiquetas de acuerdo a un patrón en particular. El repositorio fuente de Git, por ejemplo, contiene mas de 240 etiquetas. Si solo estás interesado en la serie 1.4.2, puedes ejecutar esto: $ git tag -l 'v1.4.2.*' v1.4.2.1 @@ -990,7 +1024,7 @@ Si no tienes la clave pública del autor de la firma, se obtiene algo parecido a ### Etiquetando más tarde ### -Puedes incluso etiquetar confirmaciones después de avanzar sobre ellos. Supón que tu historico de confirmaciones se parece a esto: +Puedes incluso etiquetar confirmaciones después de avanzar sobre ellas. Supón que tu historico de confirmaciones se parece a esto: $ git log --pretty=oneline 15027957951b64cf874c3557a0f3547bd83b3ff6 Merge branch 'experiment' @@ -1006,7 +1040,7 @@ Puedes incluso etiquetar confirmaciones después de avanzar sobre ellos. Supón Ahora, supón que olvidaste etiquetar el proyecto en v1.2, que estaba en la confirmación "updated rakefile". Puedes hacerlo ahora. Para etiquetar esa confirmación especifica la suma de comprobación de la confirmación (o una parte de la misma) al final del comando: - $ git tag -a v1.2 9fceb02 + $ git tag -a v1.2 -m 'version 1.2' 9fceb02 Puedes ver que has etiquetado la confirmación: @@ -1033,7 +1067,7 @@ Puedes ver que has etiquetado la confirmación: ### Compartiendo etiquetas ### -Por defecto, el comando `git push` no transfiere etiquetas a servidores remotos. Tienes que enviarlas explicitamente a un servidor compartido después de haberlas creado. Este proceso es igual a compartir ramas remotas —puedes ejecutar `git push origin [tagname]`—. +Por defecto, el comando `git push` no transfiere etiquetas a servidores remotos. Tienes que enviarlas explicitamente a un servidor compartido después de haberlas creado. Este proceso es igual a compartir ramas remotas —puedes ejecutar `git push origin [tagname]`. $ git push origin v1.5 Counting objects: 50, done. @@ -1043,7 +1077,7 @@ Por defecto, el comando `git push` no transfiere etiquetas a servidores remotos. To git@github.com:schacon/simplegit.git * [new tag] v1.5 -> v1.5 -Si tienes un montón de etiquetas que quieres enviar a la vez, también puedes usar la opción `--tags` en el comando `git push`. Esto transifere todas tus etiquetas que no estén ya en el servidor remoto. +Si tienes un montón de etiquetas que quieres enviar a la vez, también puedes usar la opción `--tags` en el comando `git push`. Esto transfiere todas tus etiquetas que no estén ya en el servidor remoto. $ git push origin --tags Counting objects: 50, done. @@ -1061,17 +1095,17 @@ Ahora, cuando alguien clone o reciba de tu repositorio, obtendrá también todas ## Consejos y trucos ## -Antes de que terminemos este capitulo de Git básico, unos pocos trucos y consejos que harán de tu experiencia con Git más sencilla, fácil, o más familiar. Mucha gente usa Git sin usar ninguno de estos consejos, y no nos referiremos a ellos o asumiremos que los has usado más tarde en el libro, pero probablemente debas saber como hacerlos. +Antes de que terminemos este capitulo de Git básico, unos pocos trucos y consejos que harán de tu experiencia con Git más sencilla, fácil, o más familiar. Mucha gente usa Git sin usar ninguno de estos consejos, y no nos referiremos a ellos o asumiremos que los has usado más tarde en el libro, pero probablemente debas saber cómo hacerlos. ### Autocompletado ### -Si usas el shell Bash, Git viene con un buen script de autocompletado que puedes activar. Descarga el código fuente de Git y busca en el directorio `contrib/completion`; ahí debe haber un archivo llamado `git-completion.bash`. Copia este fichero en tu directorio `home` y añade esto a tu archivo `.bashrc`: +Si usas el shell Bash, Git viene con un buen script de autocompletado que puedes activar. Descárgalo directamente desde el código fuente de Git en `https://github.com/git/git/blob/master/contrib/completion/git-completion.bash`, copia este fichero en tu directorio `home` y añade esto a tu archivo `.bashrc`: - source ~/.git-completion.bash + source ~/git-completion.bash -Si quieres que Git tenga automáticamente autocompletado para todos los usuarios, copia este script en el directorio `/opt/local/etc/bash_completion.d` en sistemas Mac, o en el directorio `/etc/bash_completion.d/` en sistemas Linux. Este es un directorio de scripts que Bash cargará automáticamente para proveer de autocompletado. +Si quieres que Git tenga automáticamente autocompletado para todos los usuarios, copia este script en el directorio `/opt/local/etc/bash_completion.d` en sistemas Mac, o en el directorio `/etc/bash_completion.d/` en sistemas Linux. Este es un directorio de scripts que Bash cargará automáticamente para proveer de autocompletado. -Si estas usando Windows con el Bash de Git, el cual es el predeterminado cuando instalas Git en Windows con msysGit, el autocompletado debería estar preconfigurado. +Si estás usando Windows con el Bash de Git, el cual es el predeterminado cuando instalas Git en Windows con msysGit, el autocompletado debería estar preconfigurado. Presiona el tabulador cuando estés escribiendo un comando de Git, y deberían aparecer un conjunto de sugerencias para que escojas: @@ -1080,7 +1114,7 @@ Presiona el tabulador cuando estés escribiendo un comando de Git, y deberían a En este caso, escribiendo `git co` y presionando el tabulador dos veces sugiere `commit` y `config`. Añadiendo `m` y pulsando el tabulador completa `git commit` automáticamente. -Esto también funciona con optiones, que probablemente es más útil. Por ejemplo, si quieres ejecutar `git log` y no recuerdas una de las opciones, puedes empezar a escribirla y presionar el tabulador para ver que coincide: +Esto también funciona con opciones, que probablemente es más útil. Por ejemplo, si quieres ejecutar `git log` y no recuerdas una de las opciones, puedes empezar a escribirla y presionar el tabulador para ver qué coincide: $ git log --s --shortstat --since= --src-prefix= --stat --summary @@ -1128,4 +1162,4 @@ Como puedes ver, Git simplemente reemplaza el nuevo comando con lo que le pongas ## Resumen ## -En este punto puedes hacer todas las operaciones básicas de Git a nivel local —crear o clonar un repositorio, hacer cambios, preparar y confirmar esos cambios y ver la historioa de los cambios en el repositorio—. A continuación cubriremos la mejor característica de Git: su modelo de ramas. +En este punto puedes hacer todas las operaciones básicas de Git a nivel local —crear o clonar un repositorio, hacer cambios, preparar y confirmar esos cambios y ver la historia de los cambios en el repositorio—. A continuación cubriremos la mejor característica de Git: su modelo de ramas. diff --git a/es/03-git-branching/01-chapter3.markdown b/es/03-git-branching/01-chapter3.markdown index 8d885fb89..7ba3c8877 100644 --- a/es/03-git-branching/01-chapter3.markdown +++ b/es/03-git-branching/01-chapter3.markdown @@ -15,7 +15,7 @@ Para ilustrar esto, vamos a suponer, por ejemplo, que tienes una carpeta con tre $ git add README test.rb LICENSE $ git commit -m 'initial commit of my project' -Cuando creas una confirmación con el comando 'git commit', Git realiza sumas de control de cada subcarpeta (en el ejemplo, solamente tenemos la carpeta principal del proyecto), y guarda en el repositorio Git una copia de cada uno de los archivos contenidos en ella/s. Después, Git crea un objeto de confirmación con los metadatos pertinentes y un apuntador al nodo correspondiente del árbol de proyecto. Esto permitirá poder regenerar posteriormente dicha instantánea cuando sea necesario. +Cuando creas una confirmación con el comando `git commit`, Git realiza sumas de control de cada subcarpeta (en el ejemplo, solamente tenemos la carpeta principal del proyecto), y las guarda como objetos árbol en el repositorio Git. Después, Git crea un objeto de confirmación con los metadatos pertinentes y un apuntador al objeto árbol raiz del proyecto. Esto permitirá poder regenerar posteriormente dicha instantánea cuando sea necesario. En este momento, el repositorio de Git contendrá cinco objetos: un "blob" para cada uno de los tres archivos, un árbol con la lista de contenidos de la carpeta (más sus respectivas relaciones con los "blobs"), y una confirmación de cambios (commit) apuntando a la raiz de ese árbol y conteniendo el resto de metadatos pertinentes. Conceptualmente, el contenido del repositorio Git será algo parecido a la Figura 3-1 @@ -27,12 +27,12 @@ Si haces más cambios y vuelves a confirmar, la siguiente confirmación guardar Insert 18333fig0302.png Figura 3-2. Datos en el repositorio tras una serie de confirmaciones. -Una rama Git es simplemente un apuntador móvil apuntando a una de esas confirmaciones. La rama por defecto de Git es la rama 'master'. Con la primera confirmación de cambios que realicemos, se creará esta rama principal 'master' apuntando a dicha confirmación. En cada confirmación de cambios que realicemos, la rama irá avanzando automáticamente. Y la rama 'master' apuntará siempre a la última confirmación realizada. +Una rama Git es simplemente un apuntador móvil apuntando a una de esas confirmaciones. La rama por defecto de Git es la rama `master`. Con la primera confirmación de cambios que realicemos, se creará esta rama principal `master` apuntando a dicha confirmación. En cada confirmación de cambios que realicemos, la rama irá avanzando automáticamente. Y la rama `master` apuntará siempre a la última confirmación realizada. Insert 18333fig0303.png Figura 3-3. Apuntadores en el registro de confirmaciones de una rama. -¿Qué sucede cuando creas una nueva rama? Bueno....., simplemente se crea un nuevo apuntador para que lo puedas mover libremente. Por ejemplo, si quieres crear una nueva rama denominada "testing". Usarás el comando 'git branch': +¿Qué sucede cuando creas una nueva rama? Bueno..., simplemente se crea un nuevo apuntador para que lo puedas mover libremente. Por ejemplo, si quieres crear una nueva rama denominada "testing". Usarás el comando `git branch`: $ git branch testing @@ -41,21 +41,21 @@ Esto creará un nuevo apuntador apuntando a la misma confirmación donde estés Insert 18333fig0304.png Figura 3-4. Apuntadores de varias ramas en el registro de confirmaciones de cambio. -Y, ¿cómo sabe Git en qué rama estás en este momento? Pues...., mediante un apuntador especial denominado HEAD. Aunque es preciso comentar que este HEAD es totalmente distinto al concepto de HEAD en otros sistemas de control de cambios como Subversion o CVS. En Git, es simplemente el apuntador a la rama local en la que tú estés en ese momento. En este caso, en la rama 'master'. Puesto que el comando git branch solamente crea una nueva rama, y no salta a dicha rama. +Y, ¿cómo sabe Git en qué rama estás en este momento? Pues..., mediante un apuntador especial denominado HEAD. Aunque es preciso comentar que este HEAD es totalmente distinto al concepto de HEAD en otros sistemas de control de cambios como Subversion o CVS. En Git, es simplemente el apuntador a la rama local en la que tú estés en ese momento. En este caso, en la rama `master`. Puesto que el comando git branch solamente crea una nueva rama, y no salta a dicha rama. Insert 18333fig0305.png Figura 3-5. Apuntador HEAD a la rama donde estás actualmente. -Para saltar de una rama a otra, tienes que utilizar el comando 'git checkout'. Hagamos una prueba, saltando a la rama 'testing' recién creada: +Para saltar de una rama a otra, tienes que utilizar el comando `git checkout`. Hagamos una prueba, saltando a la rama `testing` recién creada: $ git checkout testing -Esto mueve el apuntador HEAD a la rama 'testing' (ver Figura 3-6). +Esto mueve el apuntador HEAD a la rama `testing` (ver Figura 3-6). Insert 18333fig0306.png Figura 3-6. Apuntador HEAD apuntando a otra rama cuando saltamos de rama. -¿Cuál es el significado de todo esto?. Bueno.... lo veremos tras realizar otra confirmación de cambios: +¿Cuál es el significado de todo esto?. Bueno... lo veremos tras realizar otra confirmación de cambios: $ vim test.rb $ git commit -a -m 'made a change' @@ -65,7 +65,7 @@ La Figura 3-7 ilustra el resultado. Insert 18333fig0307.png Figura 3-7. La rama apuntada por HEAD avanza con cada confirmación de cambios. -Observamos algo interesante: la rama 'testing' avanza, mientras que la rama 'master' permanece en la confirmación donde estaba cuando lanzaste el comando 'git checkout' para saltar. Volvamos ahora a la rama 'master': +Observamos algo interesante: la rama `testing` avanza, mientras que la rama `master` permanece en la confirmación donde estaba cuando lanzaste el comando `git checkout` para saltar. Volvamos ahora a la rama `master`: $ git checkout master @@ -74,21 +74,21 @@ La Figura 3-8 muestra el resultado. Insert 18333fig0308.png Figura 3-8. HEAD apunta a otra rama cuando hacemos un checkout. -Este comando realiza dos acciones: Mueve el apuntador HEAD de nuevo a la rama 'master', y revierte los archivos de tu directorio de trabajo; dejandolos tal y como estaban en la última instantánea confirmada en dicha rama 'master'. Esto supone que los cambios que hagas desde este momento en adelante divergerán de la antigua versión del proyecto. Básicamente, lo que se está haciendo es rebobinar el trabajo que habias hecho temporalmente en la rama 'testing'; de tal forma que puedas avanzar en otra dirección diferente. +Este comando realiza dos acciones: Mueve el apuntador HEAD de nuevo a la rama `master`, y revierte los archivos de tu directorio de trabajo; dejándolos tal y como estaban en la última instantánea confirmada en dicha rama `master`. Esto supone que los cambios que hagas desde este momento en adelante divergirán de la antigua versión del proyecto. Básicamente, lo que se está haciendo es rebobinar el trabajo que habías hecho temporalmente en la rama `testing`; de tal forma que puedas avanzar en otra dirección diferente. Haz algunos cambios más y confirmalos: $ vim test.rb $ git commit -a -m 'made other changes' -Ahora el registro de tu proyecto diverge (ver Figura 3-9). Has creado una rama y saltado a ella, has trabajado sobre ella; has vuelto a la rama original, y has trabajado también sobre ella. Los cambios realizados en ambas sesiones de trabajo están aislados en ramas independientes: puedes saltar libremente de una a otra según estimes oportuno. Y todo ello simplemente con dos comandos: 'git branch' y 'git checkout'. +Ahora el registro de tu proyecto diverge (ver Figura 3-9). Has creado una rama y saltado a ella, has trabajado sobre ella; has vuelto a la rama original, y has trabajado también sobre ella. Los cambios realizados en ambas sesiones de trabajo están aislados en ramas independientes: puedes saltar libremente de una a otra según estimes oportuno. Y todo ello simplemente con dos comandos: `git branch` y `git checkout`. Insert 18333fig0309.png Figura 3-9. Los registros de las ramas divergen. Debido a que una rama Git es realmente un simple archivo que contiene los 40 caracteres de una suma de control SHA-1, (representando la confirmación de cambios a la que apunta), no cuesta nada el crear y destruir ramas en Git. Crear una nueva rama es tan rápido y simple como escribir 41 bytes en un archivo, (40 caracteres y un retorno de carro). -Esto contrasta fuertemente con los métodos de ramificación usados por otros sistemas de control de versiones. En los que crear una nueva rama supone el copiar todos los archivos del proyecto a una nueva carpeta adiccional. Lo que puede llevar segundos o incluso minutos, dependiendo del tamaño del proyecto. Mientras que en Git el proceso es siempre instantáneo. Y, además, debido a que se almacenan tambien los nodos padre para cada confirmación, el encontrar las bases adecuadas para realizar una fusión entre ramas es un proceso automático y generalmente sencillo de realizar. Animando así a los desarrolladores a utilizar ramificaciones frecuentemente. +Esto contrasta fuertemente con los métodos de ramificación usados por otros sistemas de control de versiones. En los que crear una nueva rama supone el copiar todos los archivos del proyecto a una nueva carpeta adicional. Lo que puede llevar segundos o incluso minutos, dependiendo del tamaño del proyecto. Mientras que en Git el proceso es siempre instantáneo. Y, además, debido a que se almacenan también los nodos padre para cada confirmación, el encontrar las bases adecuadas para realizar una fusión entre ramas es un proceso automático y generalmente sencillo de realizar. Animando así a los desarrolladores a utilizar ramificaciones frecuentemente. Y vamos a ver el por qué merece la pena hacerlo así. @@ -100,11 +100,11 @@ Vamos a presentar un ejemplo simple de ramificar y de fusionar, con un flujo de 2. Creas una rama para un nuevo tema sobre el que quieres trabajar. 3. Realizas algo de trabajo en esa rama. -En este momento, recibes una llamada avisandote de un problema crítico que has de resolver. Y sigues los siguientes pasos: +En este momento, recibes una llamada avisándote de un problema crítico que has de resolver. Y sigues los siguientes pasos: 1. Vuelves a la rama de producción original. 2. Creas una nueva rama para el problema crítico y lo resuelves trabajando en ella. -3. Tras las pertinentes pruebas, fusionas (merge) esa rama y la envias (push) a la rama de producción. +3. Tras las pertinentes pruebas, fusionas (merge) esa rama y la envías (push) a la rama de producción. 4. Vuelves a la rama del tema en que andabas antes de la llamada y continuas tu trabajo. ### Procedimientos básicos de ramificación ### @@ -114,7 +114,7 @@ Imagina que estas trabajando en un proyecto, y tienes un par de confirmaciones ( Insert 18333fig0310.png Figura 3-10. Un registro de confirmaciones simple y corto. -Decides trabajar el problema #53, del sistema que tu compañia utiliza para llevar seguimiento de los problemas. Aunque, por supuesto, Git no está ligado a ningún sistema de seguimiento de problemas concreto. Como el problema #53 es un tema concreto y puntual en el que vas a trabajar, creas una nueva rama para él. Para crear una nueva rama y saltar a ella, en un solo paso, puedes utilizar el comando 'git checkout' con la opción '-b': +Decides trabajar el problema #53, del sistema que tu compañía utiliza para llevar seguimiento de los problemas. Aunque, por supuesto, Git no está ligado a ningún sistema de seguimiento de problemas concreto. Como el problema #53 es un tema concreto y puntual en el que vas a trabajar, creas una nueva rama para él. Para crear una nueva rama y saltar a ella, en un solo paso, puedes utilizar el comando `git checkout` con la opción `-b`: $ git checkout -b iss53 Switched to a new branch "iss53" @@ -129,24 +129,24 @@ Figura 3-11 muestra el resultado. Insert 18333fig0311.png Figura 3-11. Creación de un apuntador a la nueva rama. -Trabajas en el sitio web y haces algunas confirmaciones de cambios (commits). Con ello avanzas la rama 'iss53', que es la que tienes activada (checked out) en este momento (es decir, a la que apunta HEAD; ver Figura 3-12): +Trabajas en el sitio web y haces algunas confirmaciones de cambios (commits). Con ello avanzas la rama `iss53`, que es la que tienes activada (checked out) en este momento (es decir, a la que apunta HEAD; ver Figura 3-12): $ vim index.html $ git commit -a -m 'added a new footer [issue 53]' Insert 18333fig0312.png -Figura 3-12. La rama 'iss53' ha avanzado con tu trabajo. +Figura 3-12. La rama `iss53` ha avanzado con tu trabajo. -Entonces, recibes una llamada avisandote de otro problema urgente en el sitio web. Problema que has de resolver inmediatamente. Usando Git, no necesitas mezclar el nuevo problema con los cambios que ya habias realizado sobre el problema #53; ni tampoco perder tiempo revirtiendo esos cambios para poder trabajar sobre el contenido que está en producción. Basta con saltar de nuevo a la rama 'master' y continuar trabajando a partir de ella. +Entonces, recibes una llamada avisándote de otro problema urgente en el sitio web. Problema que has de resolver inmediatamente. Usando Git, no necesitas mezclar el nuevo problema con los cambios que ya habías realizado sobre el problema #53; ni tampoco perder tiempo revirtiendo esos cambios para poder trabajar sobre el contenido que está en producción. Basta con saltar de nuevo a la rama `master` y continuar trabajando a partir de ella. -Pero, antes de poder hacer eso, hemos de tener en cuenta que teniendo cambios aún no confirmados en la carpeta de trabajo o en el área de preparación, Git no nos permitirá saltar a otra rama con la que podríamos tener conflictos. Lo mejor es tener siempre un estado de trabajo limpio y despejado antes de saltar entre ramas. Y, para ello, tenemos algunos procedimientos (stash y commit ammend), que vamos a ver más adelante. Por ahora, como tenemos confirmados todos los cambios, podemos saltar a la rama 'master' sin problemas: +Pero, antes de poder hacer eso, hemos de tener en cuenta que teniendo cambios aún no confirmados en la carpeta de trabajo o en el área de preparación, Git no nos permitirá saltar a otra rama con la que podríamos tener conflictos. Lo mejor es tener siempre un estado de trabajo limpio y despejado antes de saltar entre ramas. Y, para ello, tenemos algunos procedimientos (stash y commit ammend), que vamos a ver más adelante. Por ahora, como tenemos confirmados todos los cambios, podemos saltar a la rama `master` sin problemas: $ git checkout master Switched to branch "master" Tras esto, tendrás la carpeta de trabajo exactamente igual a como estaba antes de comenzar a trabajar sobre el problema #53. Y podrás concentrarte en el nuevo problema urgente. Es importante recordar que Git revierte la carpeta de trabajo exactamente al estado en que estaba en la confirmación (commit) apuntada por la rama que activamos (checkout) en cada momento. Git añade, quita y modifica archivos automáticamente. Para asegurarte que tu copia de trabajo es exactamente tal y como era la rama en la última confirmación de cambios realizada sobre ella. -Volviendo al problema urgente. Vamos a crear una nueva rama 'hotfix', sobre la que trabajar hasta resolverlo (ver Figura 3-13): +Volviendo al problema urgente. Vamos a crear una nueva rama `hotfix`, sobre la que trabajar hasta resolverlo (ver Figura 3-13): $ git checkout -b 'hotfix' Switched to a new branch "hotfix" @@ -156,9 +156,9 @@ Volviendo al problema urgente. Vamos a crear una nueva rama 'hotfix', sobre la q 1 files changed, 0 insertions(+), 1 deletions(-) Insert 18333fig0313.png -Figura 3-13. rama 'hotfix' basada en la rama 'master' original. +Figura 3-13. rama `hotfix` basada en la rama `master` original. -Puedes realizar las pruebas oportunas, asegurarte que la solución es correcta, e incorporar los cambios a la rama 'master' para ponerlos en producción. Esto se hace con el comando 'git merge': +Puedes realizar las pruebas oportunas, asegurarte que la solución es correcta, e incorporar los cambios a la rama `master` para ponerlos en producción. Esto se hace con el comando `git merge`: $ git checkout master $ git merge hotfix @@ -167,19 +167,19 @@ Puedes realizar las pruebas oportunas, asegurarte que la solución es correcta, README | 1 - 1 files changed, 0 insertions(+), 1 deletions(-) -Merece destacar la frase "Avance rápido" ("Fast forward") que aparece en la respuesta al comando. Git ha movido el apuntador hacia adelante, ya que la confirmación apuntada en la rama donde has fusionado estaba directamente "aguas arriba" respecto de la confirmación actual. Dicho de otro modo: cuando intentas fusionar una confirmación con otra confirmación accesible siguiendo directamente el registro de la primera; Git simplifica las cosas avanzando el puntero, ya que no hay ningûn otro trabajo divergente a fusionar. Esto es lo que se denomina "avance rápido" ("fast forward"). +Merece destacar la frase "Avance rápido" ("Fast forward") que aparece en la respuesta al comando. Git ha movido el apuntador hacia adelante, ya que la confirmación apuntada en la rama donde has fusionado estaba directamente "aguas arriba" respecto de la confirmación actual. Dicho de otro modo: cuando intentas fusionar una confirmación con otra confirmación accesible siguiendo directamente el registro de la primera; Git simplifica las cosas avanzando el puntero, ya que no hay ningún otro trabajo divergente a fusionar. Esto es lo que se denomina "avance rápido" ("fast forward"). -Ahora, los cambios realizados están ya en la instantánea (snapshot) de la confirmación (commit) apuntada por la rama 'master'. Y puedes desplegarlos (ver Figura 3-14) +Ahora, los cambios realizados están ya en la instantánea (snapshot) de la confirmación (commit) apuntada por la rama `master`. Y puedes desplegarlos (ver Figura 3-14) Insert 18333fig0314.png -Figura 3-14. Tras la fusión (merge), la rama 'master' apunta al mismo sitio que la rama 'hotfix'. +Figura 3-14. Tras la fusión (merge), la rama `master` apunta al mismo sitio que la rama `hotfix`. -Tras haber resuelto el problema urgente que te habia interrumpido tu trabajo, puedes volver a donde estabas. Pero antes, es interesante borrar la rama 'hotfix'. Ya que no la vamos a necesitar más, puesto que apunta exactamente al mismo sitio que la rama 'master'. Esto lo puedes hacer con la opción '-d' del comando 'git branch': +Tras haber resuelto el problema urgente que te había interrumpido tu trabajo, puedes volver a donde estabas. Pero antes, es interesante borrar la rama `hotfix`. Ya que no la vamos a necesitar más, puesto que apunta exactamente al mismo sitio que la rama `master`. Esto lo puedes hacer con la opción `-d` del comando `git branch`: $ git branch -d hotfix Deleted branch hotfix (3a0874c). -Y, con esto, ya estas dispuesto para regresar al trabajo sobre el problema #53 (ver Figura 3-15): +Y, con esto, ya estás dispuesto para regresar al trabajo sobre el problema #53 (ver Figura 3-15): $ git checkout iss53 Switched to branch "iss53" @@ -189,13 +189,13 @@ Y, con esto, ya estas dispuesto para regresar al trabajo sobre el problema #53 ( 1 files changed, 1 insertions(+), 0 deletions(-) Insert 18333fig0315.png -Figura 3-15. La rama 'iss53' puede avanzar independientemente. +Figura 3-15. La rama `iss53` puede avanzar independientemente. -Cabe indicar que todo el trabajo realizado en la rama 'hotfix' no está en los archivos de la rama 'iss53'. Si fuera necesario agregarlos, puedes fusionar (merge) la rama 'master' sobre la rama 'iss53' utilizando el comando 'git merge master'. O puedes esperar hasta que decidas llevar (pull) la rama 'iss53' a la rama 'master'. +Cabe indicar que todo el trabajo realizado en la rama `hotfix` no está en los archivos de la rama `iss53`. Si fuera necesario agregarlos, puedes fusionar (merge) la rama `master` sobre la rama `iss53` utilizando el comando `git merge master`. O puedes esperar hasta que decidas llevar (pull) la rama `iss53` a la rama `master`. ### Procedimientos básicos de fusión ### -Supongamos que tu trabajo con el problema #53 está ya completo y listo para fusionarlo (merge) con la rama 'master'. Para ello, de forma similar a como antes has hecho con la rama 'hotfix', vas a fusionar la rama 'iss53'. Simplemente, activando (checkout) la rama donde deseas fusionar y lanzando el comando 'git merge': +Supongamos que tu trabajo con el problema #53 está ya completo y listo para fusionarlo (merge) con la rama `master`. Para ello, de forma similar a como antes has hecho con la rama `hotfix`, vas a fusionar la rama `iss53`. Simplemente, activando (checkout) la rama donde deseas fusionar y lanzando el comando `git merge`: $ git checkout master $ git merge iss53 @@ -203,32 +203,32 @@ Supongamos que tu trabajo con el problema #53 está ya completo y listo para fus README | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) -Es algo diferente de la fusión realizada anteriormente con 'hotfix'. En este caso, el registro de desarrollo habia divergido en un punto anterior. Debido a que la confirmación en la rama actual no es ancestro directo de la rama que pretendes fusionar, Git tiene cierto trabajo extra que hacer. Git realizará una fusión a tres bandas, utilizando las dos instantáneas apuntadas por el extremo de cada una de las ramas y por el ancestro común a ambas dos. La figura 3-16 ilustra las tres instantáneas que Git utiliza para realizar la fusión en este caso. +Es algo diferente de la fusión realizada anteriormente con `hotfix`. En este caso, el registro de desarrollo había divergido en un punto anterior. Debido a que la confirmación en la rama actual no es ancestro directo de la rama que pretendes fusionar, Git tiene cierto trabajo extra que hacer. Git realizará una fusión a tres bandas, utilizando las dos instantáneas apuntadas por el extremo de cada una de las ramas y por el ancestro común a ambas dos. La figura 3-16 ilustra las tres instantáneas que Git utiliza para realizar la fusión en este caso. Insert 18333fig0316.png Figura 3-16. Git identifica automáticamente el mejor ancestro común para realizar la fusión de las ramas. En lugar de simplemente avanzar el apuntador de la rama, Git crea una nueva instantánea (snapshot) resultante de la fusión a tres bandas; y crea automáticamente una nueva confirmación de cambios (commit) que apunta a ella. Nos referimos a este proceso como "fusión confirmada". Y se diferencia en que tiene más de un padre. -Merece la pena destacar el hecho de que es el propio Git quien determina automáticamente el mejor ancestro común para realizar la fusión. Diferenciandose de otros sistemas tales como CVS o Subversion, donde es el desarrollador quien ha de imaginarse cuál puede ser dicho mejor ancestro común. Esto hace que en Git sea mucho más facil el realizar fusiones. +Merece la pena destacar el hecho de que es el propio Git quien determina automáticamente el mejor ancestro común para realizar la fusión. Diferenciandose de otros sistemas tales como CVS o Subversion, donde es el desarrollador quien ha de imaginarse cuál puede ser dicho mejor ancestro común. Esto hace que en Git sea mucho más fácil el realizar fusiones. Insert 18333fig0317.png Figura 3-17. Git crea automáticamente una nueva confirmación para la fusión. -Ahora que todo tu trabajo está ya fusionado con la rama principal, ya no tienes necesidad de la rama 'iss53'. Por lo que puedes borrarla. Y cerrar manualmente el problema en el sistema de seguimiento de problemas de tu empresa. +Ahora que todo tu trabajo está ya fusionado con la rama principal, ya no tienes necesidad de la rama `iss53`. Por lo que puedes borrarla. Y cerrar manualmente el problema en el sistema de seguimiento de problemas de tu empresa. $ git branch -d iss53 ### Principales conflictos que pueden surgir en las fusiones ### -En algunas ocasiones, los procesos de fusión no suelen ser fluidos. Si hay modificaciones dispares en una misma porción de un mismo archivo en las dos ramas distintas que pretendes fusionar, Git no será capaz de fusionarlas directamente. Por ejemplo, si en tu trabajo del problema #53 has modificado una misma porción que también ha sido modificada en el problema 'hotfix'. Puedes obtener un conflicto de fusión tal que: +En algunas ocasiones, los procesos de fusión no suelen ser fluidos. Si hay modificaciones dispares en una misma porción de un mismo archivo en las dos ramas distintas que pretendes fusionar, Git no será capaz de fusionarlas directamente. Por ejemplo, si en tu trabajo del problema #53 has modificado una misma porción que también ha sido modificada en el problema `hotfix`. Puedes obtener un conflicto de fusión tal que: $ git merge iss53 Auto-merging index.html CONFLICT (content): Merge conflict in index.html Automatic merge failed; fix conflicts and then commit the result. -Git no crea automáticamente una nueva fusión confirmada (merge commit). Sino que hace una pausa en el proceso, esperando a que tu resuelvas el conflicto. Para ver qué archivos permanecen sin fusionar en un determinado momento conflictivo de una fusión, puedes usar el comando 'git status': +Git no crea automáticamente una nueva fusión confirmada (merge commit). Sino que hace una pausa en el proceso, esperando a que tu resuelvas el conflicto. Para ver qué archivos permanecen sin fusionar en un determinado momento conflictivo de una fusión, puedes usar el comando `git status`: [master*]$ git status index.html: needs merge @@ -250,14 +250,14 @@ Todo aquello que sea conflictivo y no se haya podido resolver, se marca como "si >>>>>>> iss53:index.html -Donde nos dice que la versión en HEAD (la rama 'master', la que habias activado antes de lanzar el comando de fusión), contiene lo indicado en la parte superior del bloque (todo lo que está encima de '======='). Y que la versión en 'iss53' contiene el resto, lo indicado en la parte inferior del bloque. Para resolver el conflicto, has de elegir manualmente contenido de uno o de otro lado. Por ejemplo, puedes optar por cambiar el bloque, dejandolo tal que: +Donde nos dice que la versión en HEAD (la rama `master`, la que habias activado antes de lanzar el comando de fusión), contiene lo indicado en la parte superior del bloque (todo lo que está encima de `=======`). Y que la versión en `iss53` contiene el resto, lo indicado en la parte inferior del bloque. Para resolver el conflicto, has de elegir manualmente contenido de uno o de otro lado. Por ejemplo, puedes optar por cambiar el bloque, dejándolo tal que: -Esta corrección contiene un poco de ambas partes. Y se han eliminado completamente las líneas `<<<<<<<` , `=======` y `>>>>>>>` Tras resolver todos los bloques conflictivos, has de lanzar comandos 'git add' para marcar cada archivo modificado. Marcar archivos como preparados (staging), indica a Git que sus conflictos han sido resueltos. -Si, en lugar de resolver directamente, prefieres utilizar una herramienta gráfica. Puedes usar el comando 'git mergetool'. Esto arrancará la correspondiente herramienta de visualización y te permirá ir resolviendo conflictos con ella. +Esta corrección contiene un poco de ambas partes. Y se han eliminado completamente las líneas `<<<<<<<` , `=======` y `>>>>>>>` Tras resolver todos los bloques conflictivos, has de lanzar comandos `git add` para marcar cada archivo modificado. Marcar archivos como preparados (staging), indica a Git que sus conflictos han sido resueltos. +Si en lugar de resolver directamente, prefieres utilizar una herramienta gráfica, puedes usar el comando `git mergetool`. Esto arrancará la correspondiente herramienta de visualización y te permitirá ir resolviendo conflictos con ella. $ git mergetool merge tool candidates: kdiff3 tkdiff xxdiff meld gvimdiff opendiff emerge vimdiff @@ -268,11 +268,11 @@ Si, en lugar de resolver directamente, prefieres utilizar una herramienta gráfi {remote}: modified Hit return to start merge resolution tool (opendiff): -Si deseas usar una herramienta distinta de la escogida por defecto (en mi caso 'opendiff', porque estoy lanzando el comando en un Mac), puedes escogerla entre la lista de herramientas soportadas mostradas al principio ("merge tool candidates"). Tecleando el nombre de dicha herramienta. En el capítulo 7 se verá cómo cambiar este valor por defecto de tu entorno de trabajo. +Si deseas usar una herramienta distinta de la escogida por defecto (en mi caso `opendiff`, porque estoy lanzando el comando en un Mac), puedes escogerla entre la lista de herramientas soportadas mostradas al principio ("merge tool candidates"). Tecleando el nombre de dicha herramienta. En el capítulo 7 se verá cómo cambiar este valor por defecto de tu entorno de trabajo. Tras salir de la herramienta de fusionado, Git preguntará a ver si hemos resuelto todos los conflictos y la fusión ha sido satisfactoria. Si le indicas que así ha sido, Git marca como preparado (staged) el archivo que acabamos de modificar. -En cualquier momento, puedes lanzar el comando 'git status' para ver si ya has resuelto todos los conflictos: +En cualquier momento, puedes lanzar el comando `git status` para ver si ya has resuelto todos los conflictos: $ git status # On branch master @@ -282,7 +282,7 @@ En cualquier momento, puedes lanzar el comando 'git status' para ver si ya has r # modified: index.html # -Si todo ha ido correctamente, y ves que todos los archivos conflictivos están marcados como preparados, puedes lanzar el comando 'git commit' para terminar de confirmar la fusión. El mensaje de confirmación por defecto será algo parecido a: +Si todo ha ido correctamente, y ves que todos los archivos conflictivos están marcados como preparados, puedes lanzar el comando `git commit` para terminar de confirmar la fusión. El mensaje de confirmación por defecto será algo parecido a: Merge branch 'iss53' @@ -295,46 +295,46 @@ Si todo ha ido correctamente, y ves que todos los archivos conflictivos están m # and try again. # -Puedes modificar este mensaje añadiendo detalles sobre cómo has resuelto la fusión, si lo consideras util para que otros entiendan esta fusión en un futuro. Se trata de indicar porqué has hecho lo que has hecho; a no ser que resulte obvio, claro está. +Puedes modificar este mensaje añadiendo detalles sobre cómo has resuelto la fusión, si lo consideras útil para que otros entiendan esta fusión en un futuro. Se trata de indicar porqué has hecho lo que has hecho; a no ser que resulte obvio, claro está. ## Gestión de ramificaciones ## Ahora que ya has creado, fusionado y borrado algunas ramas, vamos a dar un vistazo a algunas herramientas de gestión muy útiles cuando comienzas a utilizar ramas profusamente. -El comando 'git branch' tiene más funciones que las de crear y borrar ramas. Si lo lanzas sin argumentos, obtienes una lista de las ramas presentes en tu proyecto: +El comando `git branch` tiene más funciones que las de crear y borrar ramas. Si lo lanzas sin argumentos, obtienes una lista de las ramas presentes en tu proyecto: $ git branch iss53 * master testing -Fijate en el carácter `*` delante de la rama 'master': nos indica la rama activa en este momento. Si hacemos una confirmación de cambios (commit), esa será la rama que avance. Para ver la última confirmación de cambios en cada rama, puedes usar el comando 'git branch -v': +Fijate en el carácter `*` delante de la rama `master`: nos indica la rama activa en este momento. Si hacemos una confirmación de cambios (commit), esa será la rama que avance. Para ver la última confirmación de cambios en cada rama, puedes usar el comando `git branch -v`: $ git branch -v iss53 93b412c fix javascript issue * master 7a98805 Merge branch 'iss53' testing 782fd34 add scott to the author list in the readmes -Otra opción útil para averiguar el estado de las ramas, es filtrarlas y mostrar solo aquellas que han sido fusionadas (o que no lo han sido) con la rama actualmente activa. Para ello, Git dispone, desde la versión 1.5.6, las opciones '--merged' y '--no-merged'. Si deseas ver las ramas que han sido fusionadas en la rama activa, puedes lanzar el comando 'git branch --merged': +Otra opción útil para averiguar el estado de las ramas, es filtrarlas y mostrar solo aquellas que han sido fusionadas (o que no lo han sido) con la rama actualmente activa. Para ello, Git dispone, desde la versión 1.5.6, las opciones `--merged` y `--no-merged`. Si deseas ver las ramas que han sido fusionadas en la rama activa, puedes lanzar el comando `git branch --merged`: $ git branch --merged iss53 * master -Aparece la rama 'iss53' porque ya ha sido fusionada. Y no lleva por delante el caracter `*` porque todo su contenido ya ha sido incorporado a otras ramas. Podemos borrarla tranquilamente con 'git branch -d', sin miedo a perder nada. +Aparece la rama `iss53` porque ya ha sido fusionada. Y no lleva por delante el caracter `*` porque todo su contenido ya ha sido incorporado a otras ramas. Podemos borrarla tranquilamente con `git branch -d`, sin miedo a perder nada. -Para mostrar todas las ramas que contienen trabajos sin fusionar aún, puedes utilizar el comando 'git branch --no-merged': +Para mostrar todas las ramas que contienen trabajos sin fusionar aún, puedes utilizar el comando `git branch --no-merged`: $ git branch --no-merged testing -Esto nos muestra la otra rama en el proyecto. Debido a que contiene trabajos sin fusionar aún, al intentarla borrar con 'git branch -d', el comando nos dará un error: +Esto nos muestra la otra rama en el proyecto. Debido a que contiene trabajos sin fusionar aún, al intentarla borrar con `git branch -d`, el comando nos dará un error: $ git branch -d testing error: The branch 'testing' is not an ancestor of your current HEAD. If you are sure you want to delete it, run 'git branch -D testing'. -Si realmente deseas borrar la rama, y perder el trabajo contenido en ella, puedes forzar el borrado con la opción '-D'; tal y como lo indica el mensaje de ayuda. +Si realmente deseas borrar la rama, y perder el trabajo contenido en ella, puedes forzar el borrado con la opción `-D`; tal y como lo indica el mensaje de ayuda. ## Flujos de trabajo ramificados ## @@ -342,9 +342,9 @@ Ahora que ya has visto los procedimientos básicos de ramificación y fusión, ### Ramas de largo recorrido ### -Por la sencillez de la fusión a tres bandas de Git, el fusionar de una rama a otra multitud de veces a lo largo del tiempo es facil de hacer. Esto te posibilita tener varias ramas siempre abiertas, e irlas usando en diferentes etapas del ciclo de desarrollo; realizando frecuentes fusiones entre ellas. +Por la sencillez de la fusión a tres bandas de Git, el fusionar de una rama a otra multitud de veces a lo largo del tiempo es fácil de hacer. Esto te posibilita tener varias ramas siempre abiertas, e irlas usando en diferentes etapas del ciclo de desarrollo; realizando frecuentes fusiones entre ellas. -Muchos desarrolladores que usan Git llevan un flujo de trabajo de esta naturaleza, manteniendo en la rama 'master' únicamente el código totalmente estable (el código que ha sido o que va a ser liberado). Teniendo otras ramas paralelas denominadas 'desarrollo' o 'siguiente', en las que trabajan y realizan pruebas. Estas ramas paralelas no suele estar siempre en un estado estable; pero cada vez que sí lo están, pueden ser fusionadas con la rama 'master'. También es habitual el incorporarle (pull) ramas puntuales (ramas temporales, como la rama 'iss53' del anterior ejemplo) cuando las completamos y estamos seguros de que no van a introducir errores. +Muchos desarrolladores que usan Git llevan un flujo de trabajo de esta naturaleza, manteniendo en la rama `master` únicamente el código totalmente estable (el código que ha sido o que va a ser liberado). Teniendo otras ramas paralelas denominadas `desarrollo` o `siguiente`, en las que trabajan y realizan pruebas. Estas ramas paralelas no suele estar siempre en un estado estable; pero cada vez que sí lo están, pueden ser fusionadas con la rama `master`. También es habitual el incorporarle (pull) ramas puntuales (ramas temporales, como la rama `iss53` del anterior ejemplo) cuando las completamos y estamos seguros de que no van a introducir errores. En realidad, en todo momento estamos hablando simplemente de apuntadores moviendose por la línea temporal de confirmaciones de cambio (commit history). Las ramas estables apuntan hacia posiciones más antiguas en el registro de confirmaciones. Mientras que las ramas avanzadas, las que van abriendo camino, apuntan hacia posiciones más recientes. @@ -356,63 +356,63 @@ Podría ser más sencillo pensar en las ramas como si fueran silos de almacenami Insert 18333fig0319.png Figura 3-19. Puede ayudar pensar en las ramas como silos de almacenamiento. -Este sistema de trabajo se puede ampliar para diversos grados de estabilidad. Algunos proyectos muy grandes suelen tener una rama denominada 'propuestas' o 'pu' (proposed updates). Donde suele estar todo aquello integrado desde otras ramas, pero que aún no está listo para ser incorporado a las ramas 'siguiente' o 'master'. La idea es mantener siempre diversas ramas en diversos grados de estabilidad; pero cuando alguna alcanza un estado más estable, la fusionamos con la rama inmediatamente superior a ella. +Este sistema de trabajo se puede ampliar para diversos grados de estabilidad. Algunos proyectos muy grandes suelen tener una rama denominada `propuestas` o `pu` (proposed updates). Donde suele estar todo aquello integrado desde otras ramas, pero que aún no está listo para ser incorporado a las ramas `siguiente` o `master`. La idea es mantener siempre diversas ramas en diversos grados de estabilidad; pero cuando alguna alcanza un estado más estable, la fusionamos con la rama inmediatamente superior a ella. Aunque no es obligatorio el trabajar con ramas de larga duración, realmente es práctico y útil. Sobre todo en proyectos largos o complejos. ### Ramas puntuales ### Las ramas puntuales, en cambio, son útiles en proyectos de cualquier tamaño. Una rama puntual es aquella de corta duración que abres para un tema o para una funcionalidad muy concretos. Es algo que nunca habrías hecho en otro sistema VCS, debido a los altos costos de crear y fusionar ramas que se suelen dar en esos sistemas. Pero en Git, por el contrario, es muy habitual el crear, trabajar con, fusionar y borrar ramas varias veces al día. -Tal y como has visto con las ramas 'iss53' y 'hotfix' que has creado en la sección anterior. Has hecho unas pocas confirmaciones de cambio en ellas, y luego las has borrado tras fusionarlas con la rama principal. Esta técnica te posibilita realizar rápidos y completos saltos de contexto. Y, debido a que el trabajo está claramente separado en silos, con todos los cambios de cada tema en su propia rama, te será mucho más sencillo revisar el código y seguir su evolución. Puedes mantener los cambios ahí durante minutos, dias o meses; y fusionarlos cuando realmente estén listos. En lugar de verte obligado a fusionarlos en el orden en que fueron creados y comenzaste a trabajar en ellos. +Tal y como has visto con las ramas `iss53` y `hotfix` que has creado en la sección anterior. Has hecho unas pocas confirmaciones de cambio en ellas, y luego las has borrado tras fusionarlas con la rama principal. Esta técnica te posibilita realizar rápidos y completos saltos de contexto. Y, debido a que el trabajo está claramente separado en silos, con todos los cambios de cada tema en su propia rama, te será mucho más sencillo revisar el código y seguir su evolución. Puedes mantener los cambios ahí durante minutos, dias o meses; y fusionarlos cuando realmente estén listos. En lugar de verte obligado a fusionarlos en el orden en que fueron creados y comenzaste a trabajar en ellos. -Por ejemplo, puedes realizar cierto trabajo en la rama 'master', ramificar para un problema concreto (rama 'iss91'), trabajar en él un rato, ramificar a una segunda rama para probar otra manera de resolverlo (rama 'iss92v2'), volver a la rama 'master' y trabajar un poco más, y, por último, ramificar temporalmente para probar algo de lo que no estás seguro (rama 'dumbidea'). El registro de confirmaciones (commit history) será algo parecido a la Figura 3-20. +Por ejemplo, puedes realizar cierto trabajo en la rama `master`, ramificar para un problema concreto (rama `iss91`), trabajar en él un rato, ramificar a una segunda rama para probar otra manera de resolverlo (rama `iss92v2`), volver a la rama `master` y trabajar un poco más, y, por último, ramificar temporalmente para probar algo de lo que no estás seguro (rama `dumbidea`). El registro de confirmaciones (commit history) será algo parecido a la Figura 3-20. Insert 18333fig0320.png Figura 3-20. El registro de confirmaciones con múltiples ramas puntuales. -En este momento, supongamos que te decides por la segunda solución al problema (rama 'iss92v2'); y que, tras mostrar la rama 'dumbidea' a tus compañeros, resulta que les parece una idea genial. Puedes descartar la rama 'iss91' (perdiendo las confirmaciones C5 y C6), y fusionar las otras dos. El registro será algo parecido a la Figura 3-21. +En este momento, supongamos que te decides por la segunda solución al problema (rama `iss92v2`); y que, tras mostrar la rama `dumbidea` a tus compañeros, resulta que les parece una idea genial. Puedes descartar la rama `iss91` (perdiendo las confirmaciones C5 y C6), y fusionar las otras dos. El registro será algo parecido a la Figura 3-21. Insert 18333fig0321.png -Figura 3-21. El registro tras fusionar 'dumbidea' e 'iss91v2'. +Figura 3-21. El registro tras fusionar `dumbidea` e `iss91v2`. -Es importante recordar que, mientras estás haciendo todo esto, todas las ramas son completamente locales. Cuando ramificas y fusionas, todo se realiza en tu propio repositório Git. No hay nigún tipo de tráfico con ningún servidor. +Es importante recordar que, mientras estás haciendo todo esto, todas las ramas son completamente locales. Cuando ramificas y fusionas, todo se realiza en tu propio repositorio Git. No hay nigún tipo de tráfico con ningún servidor. ## Ramas Remotas ## Las ramas remotas son referencias al estado de ramas en tus repositorios remotos. Son ramas locales que no puedes mover; se mueven automáticamente cuando estableces comunicaciones en la red. Las ramas remotas funcionan como marcadores, para recordarte en qué estado se encontraban tus repositorios remotos la última vez que conectaste con ellos. -Suelen referenciarse como '(remoto)/(rama)'. Por ejemplo, si quieres saber cómo estaba la rama 'master' en el remoto 'origin'. Puedes revisar la rama 'origin/master'. O si estás trabajando en un problema con un compañero y este envia (push) una rama 'iss53', tu tendrás tu propia rama de trabajo local 'iss53'; pero la rama en el servidor apuntará a la última confirmación (commit) en la rama 'origin/iss53'. +Suelen referenciarse como `(remoto)/(rama)`. Por ejemplo, si quieres saber cómo estaba la rama `master` en el remoto `origin`. Puedes revisar la rama `origin/master`. O si estás trabajando en un problema con un compañero y este envia (push) una rama `iss53`, tu tendrás tu propia rama de trabajo local `iss53`; pero la rama en el servidor apuntará a la última confirmación (commit) en la rama `origin/iss53`. -Esto puede ser un tanto confuso, pero intentemos aclararlo con un ejemplo. Supongamos que tienes un sevidor Git en tu red, en 'git.ourcompany.com'. Si haces un clón desde ahí, Git automáticamente lo denominará 'origin', traerá (pull) sus datos, creará un apuntador hacia donde esté en ese momento su rama 'master', denominará la copia local 'origin/master'; y será inamovible para tí. Git te proporcionará también tu propia rama 'master', apuntando al mismo lugar que la rama 'master' de 'origin'; siendo en esta última donde podrás trabajar. +Esto puede ser un tanto confuso, pero intentemos aclararlo con un ejemplo. Supongamos que tienes un sevidor Git en tu red, en `git.ourcompany.com`. Si haces un clón desde ahí, Git automáticamente lo denominará `origin`, traerá (pull) sus datos, creará un apuntador hacia donde esté en ese momento su rama `master`, denominará la copia local `origin/master`; y será inamovible para ti. Git te proporcionará también tu propia rama `master`, apuntando al mismo lugar que la rama `master` de `origin`; siendo en esta última donde podrás trabajar. Insert 18333fig0322.png -Figura 3-22. Un clón Git te proporciona tu propia rama 'master' y otra rama 'origin/master' apuntando a la rama 'master' original. +Figura 3-22. Un clón Git te proporciona tu propia rama `master` y otra rama `origin/master` apuntando a la rama `master` original. -Si haces algún trabajo en tu rama 'master' local. Y, al mismo tiempo, alguna otra persona lleva (push) su trabajo al servidor 'git.ourcompany.com', actualizando la rama 'master' de allí. Te encontrarás con que ambos registros avanzan de forma diferente. Además, mientras no tengas contacto con el servidor, tu apuntador a tu rama 'origin/master' no se moverá (ver Figura 3/23). +Si haces algún trabajo en tu rama `master` local, y al mismo tiempo, alguna otra persona lleva (push) su trabajo al servidor `git.ourcompany.com`, actualizando la rama `master` de allí, te encontrarás con que ambos registros avanzan de forma diferente. Además, mientras no tengas contacto con el servidor, tu apuntador a tu rama `origin/master` no se moverá (ver Figura 3/23). Insert 18333fig0323.png Figura 3-23. Trabajando localmente y que otra persona esté llevando (push) algo al servidor remoto, hace que cada registro avance de forma distinta. -Para sincronizarte, puedes utilizar el comando 'git fetch origin'. Este comando localiza en qué servidor está el origen (en este caso 'git.ourcompany.com'), recupera cualquier dato presente allí que tu no tengas, y actualiza tu base de datos local, moviendo tu rama 'origin/master' para que apunte a esta nueva y más reciente posición (ver Figura 3-24). +Para sincronizarte, puedes utilizar el comando `git fetch origin`. Este comando localiza en qué servidor está el origen (en este caso `git.ourcompany.com`), recupera cualquier dato presente allí que tu no tengas, y actualiza tu base de datos local, moviendo tu rama `origin/master` para que apunte a esta nueva y más reciente posición (ver Figura 3-24). Insert 18333fig0324.png -Figura 3-24. El comando 'git fetch' actualiza tus referencias remotas. +Figura 3-24. El comando `git fetch` actualiza tus referencias remotas. -Para ilustrar mejor el caso de tener múltiples servidores y cómo van las ramas remotas para esos proyectos remotos. Supongamos que tienes otro servidor Git; utilizado solamente para desarrollo, por uno de tus equipos sprint. Un servidor en 'git.team1.ourcompany.com'. Puedes incluirlo como una nueva referencia remota a tu proyecto actual, mediante el comando 'git remote add', tal y como vimos en el capítulo 2. Puedes denominar 'teamone' a este remoto, poniendo este nombre abreviado para la URL (ver Figura 3-25) +Para ilustrar mejor el caso de tener múltiples servidores y cómo van las ramas remotas para esos proyectos remotos. Supongamos que tienes otro servidor Git; utilizado solamente para desarrollo, por uno de tus equipos sprint. Un servidor en `git.team1.ourcompany.com`. Puedes incluirlo como una nueva referencia remota a tu proyecto actual, mediante el comando `git remote add`, tal y como vimos en el capítulo 2. Puedes denominar `teamone` a este remoto, poniendo este nombre abreviado para la URL (ver Figura 3-25) Insert 18333fig0325.png Figura 3-25. Añadiendo otro servidor como remoto. -Ahora, puedes usar el comando 'git fetch teamone' para recuperar todo el contenido del servidor que tu no tenias. Debido a que dicho servidor es un subconjunto de de los datos del servidor 'origin' que tienes actualmente, Git no recupera (fetch) ningún dato; simplemente prepara una rama remota llamada 'teamone/master' para apuntar a la confirmación (commit) que 'teamone' tiene en su rama 'master'. +Ahora, puedes usar el comando `git fetch teamone` para recuperar todo el contenido del servidor que tu no tenias. Debido a que dicho servidor es un subconjunto de de los datos del servidor `origin` que tienes actualmente, Git no recupera (fetch) ningún dato; simplemente prepara una rama remota llamada `teamone/master` para apuntar a la confirmación (commit) que `teamone` tiene en su rama `master`. Insert 18333fig0326.png -Figura 3-26. Obtienes una referencia local a la posición en la rama 'master' de 'teamone'. +Figura 3-26. Obtienes una referencia local a la posición en la rama `master` de `teamone`. ### Publicando ### Cuando quieres compartir una rama con el resto del mundo, has de llevarla (push) a un remoto donde tengas permisos de escritura. Tus ramas locales no se sincronizan automáticamente con los remotos en los que escribes. Sino que tienes que llevar (push) expresamente, cada vez, al remoto las ramas que desees compartir. De esta forma, puedes usar ramas privadas para el trabajo que no deseas compartir. Llevando a un remoto tan solo aquellas partes que deseas aportar a los demás. -Si tienes una rama llamada 'serverfix', con la que vas a trabajar en colaboración; puedes llevarla al remoto de la misma forma que llevaste tu primera rama. Con el comando 'git push (remoto) (rama)': +Si tienes una rama llamada `serverfix`, con la que vas a trabajar en colaboración; puedes llevarla al remoto de la misma forma que llevaste tu primera rama. Con el comando `git push (remoto) (rama)`: $ git push origin serverfix Counting objects: 20, done. @@ -422,9 +422,9 @@ Si tienes una rama llamada 'serverfix', con la que vas a trabajar en colaboraci To git@github.com:schacon/simplegit.git * [new branch] serverfix -> serverfix -Esto es un poco como un atajo. Git expande automáticamente el nombre de rama 'serverfix' a 'refs/heads/serverfix:refs/heads/serverfix', que significa: "coge mi rama local 'serverfix' y actualiza con ella la rama 'serverfix' del remoto". Volveremos más tarde sobre el tema de 'refs/heads/', viendolo en detalle en el capítulo 9; aunque puedes ignorarlo por ahora. También puedes hacer 'git push origin serverfix:serverfix', que hace lo mismo; es decir: "coge mi 'serverfix' y hazlo el 'serverfix' remoto". Puedes utilizar este último formato para llevar una rama local a una rama remota con otro nombre distinto. Si no quieres que se llame 'serverfix' en el remoto, puedes lanzar, por ejemplo, 'git push origin serverfix:awesomebranch'; para llevar tu rama 'serverfix' local a la rama 'awesomebranch' en el proyecto remoto. +Esto es un poco como un atajo. Git expande automáticamente el nombre de rama `serverfix` a `refs/heads/serverfix:refs/heads/serverfix`, que significa: "coge mi rama local `serverfix` y actualiza con ella la rama `serverfix` del remoto". Volveremos más tarde sobre el tema de `refs/heads/`, viéndolo en detalle en el capítulo 9; aunque puedes ignorarlo por ahora. También puedes hacer `git push origin serverfix:serverfix`, que hace lo mismo; es decir: "coge mi `serverfix` y hazlo el `serverfix` remoto". Puedes utilizar este último formato para llevar una rama local a una rama remota con otro nombre distinto. Si no quieres que se llame `serverfix` en el remoto, puedes lanzar, por ejemplo, `git push origin serverfix:awesomebranch`; para llevar tu rama `serverfix` local a la rama `awesomebranch` en el proyecto remoto. -La próxima vez que tus colaboradores recuperen desde el servidor, obtendrán una referencia a donde la versión de 'serverfix' en el servidor esté bajo la rama remota 'origin/serverfix': +La próxima vez que tus colaboradores recuperen desde el servidor, obtendrán bajo la rama remota `origin/serverfix` una referencia a donde esté la versión de `serverfix` en el servidor: $ git fetch origin remote: Counting objects: 20, done. @@ -434,21 +434,21 @@ La próxima vez que tus colaboradores recuperen desde el servidor, obtendrán un From git@github.com:schacon/simplegit * [new branch] serverfix -> origin/serverfix -Es importante destacar que cuando recuperas (fetch) nuevas ramas remotas, no obtienes automáticamente una copia editable local de las mismas. En otras palabras, en este caso, no tienes una nueva rama 'serverfix'. Sino que únicamente tienes un puntero no editable a 'origin/serverfix'. +Es importante destacar que cuando recuperas (fetch) nuevas ramas remotas, no obtienes automáticamente una copia editable local de las mismas. En otras palabras, en este caso, no tienes una nueva rama `serverfix`. Sino que únicamente tienes un puntero no editable a `origin/serverfix`. -Para integrar (merge) esto en tu actual rama de trabajo, puedes usar el comando 'git merge origin/serverfix'. Y si quieres tener tu propia rama 'serverfix', donde puedas trabajar, puedes crearla directamente basandote en rama remota: +Para integrar (merge) esto en tu actual rama de trabajo, puedes usar el comando `git merge origin/serverfix`. Y si quieres tener tu propia rama `serverfix`, donde puedas trabajar, puedes crearla directamente basaádote en rama remota: $ git checkout -b serverfix origin/serverfix Branch serverfix set up to track remote branch refs/remotes/origin/serverfix. Switched to a new branch "serverfix"Switched to a new branch "serverfix" -Esto sí te da una rama local donde puedes trabajar, comenzando donde 'origin/serverfix' estaba en ese momento. +Esto sí te da una rama local donde puedes trabajar, comenzando donde `origin/serverfix` estaba en ese momento. ### Haciendo seguimiento a las ramas ### -Activando (checkout) una rama local a partir de una rama remota, se crea automáticamente lo que podríamos denominar "una rama de seguimiento" (tracking branch). Las ramas de seguimiento son ramas locales que tienen una relación directa con alguna rama remota. Si estás en una rama de seguimiento y tecleas el comando 'git push', Git sabe automáticamente a qué servidor y a qué rama ha de llevar los contenidos. Igualmente, tecleando 'git pull' mientras estamos en una de esas ramas, recupera (fetch) todas las referencias remotas y las consolida (merge) automáticamente en la correspondiente rama remota. +Activando (checkout) una rama local a partir de una rama remota, se crea automáticamente lo que podríamos denominar "una rama de seguimiento" (tracking branch). Las ramas de seguimiento son ramas locales que tienen una relación directa con alguna rama remota. Si estás en una rama de seguimiento y tecleas el comando `git push`, Git sabe automáticamente a qué servidor y a qué rama ha de llevar los contenidos. Igualmente, tecleando `git pull` mientras estamos en una de esas ramas, recupera (fetch) todas las referencias remotas y las consolida (merge) automáticamente en la correspondiente rama remota. -Cuando clonas un repositorio, este suele crear automáticamente una rama 'master' que hace seguimiento de 'origin/master'. Y es por eso que 'git push' y 'git pull' trabajan directamente, sin necesidad de más argumentos. Sin embargo, puedes preparar otras ramas de seguimiento si deseas tener unas que no hagan seguimiento de ramas en 'origin' y que no sigan a la rama 'master'. El ejemplo más simple, es el que acabas de ver al lanzar el comando 'git checkout -b [rama] [nombreremoto]/[rama]'. Si tienes la versión 1.6.2 de Git, o superior, puedes utilizar también el parámetro '--track': +Cuando clonas un repositorio, este suele crear automáticamente una rama `master` que hace seguimiento de `origin/master`. Y es por eso que `git push` y `git pull` trabajan directamente, sin necesidad de más argumentos. Sin embargo, puedes preparar otras ramas de seguimiento si deseas tener unas que no hagan seguimiento de ramas en `origin` y que no sigan a la rama `master`. El ejemplo más simple, es el que acabas de ver al lanzar el comando `git checkout -b [rama] [nombreremoto]/[rama]`. Si tienes la versión 1.6.2 de Git, o superior, puedes utilizar también el parámetro `--track`: $ git checkout --track origin/serverfix Branch serverfix set up to track remote branch refs/remotes/origin/serverfix. @@ -460,17 +460,17 @@ Para preparar una rama local con un nombre distinto a la del remoto, puedes util Branch sf set up to track remote branch refs/remotes/origin/serverfix. Switched to a new branch "sf" -Así, tu rama local 'sf' va a llevar (push) y traer (pull) hacia o desde 'origin/serverfix'. +Así, tu rama local `sf` va a llevar (push) y traer (pull) hacia o desde `origin/serverfix`. ### Borrando ramas remotas ### -Imagina que ya has terminado con una rama remota. Es decir, tanto tu como tus colaboradores habeis completado una determinada funcionalidad y la habeis incorporado (merge) a la rama 'master' en el remoto (o donde quiera que tengais la rama de código estable). Puedes borrar la rama remota utilizando la un tanto confusa sintaxis: 'git push [nombreremoto] :[rama]'. Por ejemplo, si quieres borrar la rama 'serverfix' del servidor, puedes utilizar: +Imagina que ya has terminado con una rama remota. Es decir, tanto tu como tus colaboradores habeis completado una determinada funcionalidad y la habeis incorporado (merge) a la rama `master` en el remoto (o donde quiera que tengais la rama de código estable). Puedes borrar la rama remota utilizando la un tanto confusa sintaxis: `git push [nombreremoto] :[rama]`. Por ejemplo, si quieres borrar la rama `serverfix` del servidor, puedes utilizar: $ git push origin :serverfix To git@github.com:schacon/simplegit.git - [deleted] serverfix -Y....Boom!. La rama en el servidor ha desaparecido. Puedes grabarte a fuego esta página, porque necesitarás ese comando y, lo más probable es que hayas olvidado su sintaxis. Una manera de recordar este comando es dándonos cuenta de que proviene de la sintaxis 'git push [nombreremoto] [ramalocal]:[ramaremota]'. Si omites la parte '[ramalocal]', lo que estás diciendo es: "no cojas nada de mi lado y haz con ello [ramaremota]". +Y... ¡Boom!. La rama en el servidor ha desaparecido. Puedes grabarte a fuego esta página, porque necesitarás ese comando y, lo más probable es que hayas olvidado su sintaxis. Una manera de recordar este comando es dándonos cuenta de que proviene de la sintaxis `git push [nombreremoto] [ramalocal]:[ramaremota]`. Si omites la parte `[ramalocal]`, lo que estás diciendo es: "no cojas nada de mi lado y haz con ello [ramaremota]". ## Reorganizando el trabajo realizado ## @@ -483,12 +483,12 @@ Volviendo al ejemplo anterior, en la sección sobre fusiones (ver Figura 3-27), Insert 18333fig0327.png Figura 3-27. El registro de confirmaciones inicial. -La manera más sencilla de integrar ramas, tal y como hemos visto, es el comando 'git merge'. Realiza una fusión a tres bandas entre las dos últimas instantáneas de cada rama (C3 y C4) y el ancestro común a ambas (C2); creando una nueva instantánea (snapshot) y la correspondiente confirmación (commit), según se muestra en la Figura 3-28. +La manera más sencilla de integrar ramas, tal y como hemos visto, es el comando `git merge`. Realiza una fusión a tres bandas entre las dos últimas instantáneas de cada rama (C3 y C4) y el ancestro común a ambas (C2); creando una nueva instantánea (snapshot) y la correspondiente confirmación (commit), según se muestra en la Figura 3-28. Insert 18333fig0328.png Figura 3-28. Fusionando una rama para integrar el registro de trabajos divergentes. -Aunque también hay otra forma de hacerlo: puedes coger los cambios introducidos en C3 y reaplicarlos encima de C4. Esto es lo que en Git llamamos _reorganizar_. Con el comando 'git rebase', puedes coger todos los cambios confirmados en una rama, y reaplicarlos sobre otra. +Aunque también hay otra forma de hacerlo: puedes coger los cambios introducidos en C3 y reaplicarlos encima de C4. Esto es lo que en Git llamamos _reorganizar_. Con el comando `git rebase`, puedes coger todos los cambios confirmados en una rama, y reaplicarlos sobre otra. Por ejemplo, puedes lanzar los comandos: @@ -502,29 +502,29 @@ Haciendo que Git: vaya al ancestro común de ambas ramas (donde estás actualmen Insert 18333fig0329.png Figura 3-29. Reorganizando sobre C4 los cambios introducidos en C3. -En este momento, puedes volver a la rama 'master' y hacer una fusión con avance rápido (fast-forward merge). (ver Figura 3-30) +En este momento, puedes volver a la rama `master` y hacer una fusión con avance rápido (fast-forward merge). (ver Figura 3-30) Insert 18333fig0330.png -Figura 3-30. Avance rápido de la rama 'master'. +Figura 3-30. Avance rápido de la rama `master`. -Así, la instantánea apuntada por C3 aquí es exactamente la misma apuntada por C5 en el ejemplo de la fusión. No hay ninguna diferencia en el resultado final de la integración, pero el haberla hecho reorganizando nos deja un registro más claro. Si examinas el registro de una rama reorganizada, este aparece siempre como un registro lineal: como si todo el trabajo se hubiera realizado en series, aunque realmente se haya hecho en paralelo. +Así, la instantánea apuntada por C3' aquí es exactamente la misma apuntada por C5 en el ejemplo de la fusión. No hay ninguna diferencia en el resultado final de la integración, pero el haberla hecho reorganizando nos deja un registro más claro. Si examinas el registro de una rama reorganizada, este aparece siempre como un registro lineal: como si todo el trabajo se hubiera realizado en series, aunque realmente se haya hecho en paralelo. -Habitualmente, optarás por esta vía cuando quieras estar seguro de que tus confirmaciones de cambio (commits) se pueden aplicar limpiamente sobre una rama remota; posiblemente, en un proyecto donde estés intentando colaborar, pero lleves tu el mantenimiento. En casos como esos, puedes trabajar sobre una rama y luego reorgainzar lo realizado en la rama 'origin/master' cuando lo tengas todo listo para enviarlo al proyecto principal. De esta forma, la persona que mantiene el proyecto no necesitará hacer ninguna integración con tu trabajo; le bastará con un avance rápido o una incorporación limpia. +Habitualmente, optarás por esta vía cuando quieras estar seguro de que tus confirmaciones de cambio (commits) se pueden aplicar limpiamente sobre una rama remota; posiblemente, en un proyecto donde estés intentando colaborar, pero lleves tu el mantenimiento. En casos como esos, puedes trabajar sobre una rama y luego reorganizar lo realizado en la rama `origin/master` cuando lo tengas todo listo para enviarlo al proyecto principal. De esta forma, la persona que mantiene el proyecto no necesitará hacer ninguna integración con tu trabajo; le bastará con un avance rápido o una incorporación limpia. -Cabe destacar que la instantánea (snapshot) apuntada por la confirmación (commit) final, tanto si es producto de una regorganización (rebase) como si lo es de una fusión (merge), es exactamente la misma instantánea. Lo único diferente es el registro. La reorganización vuelve a aplicar cambios de una rama de trabajo sobre otra rama, en el mismo orden en que fueron introducidos en la primera. Mientras que la fusión combina entre sí los dos puntos finales de ambas ramas. +Cabe destacar que la instantánea (snapshot) apuntada por la confirmación (commit) final, tanto si es producto de una reorganización (rebase) como si lo es de una fusión (merge), es exactamente la misma instantánea. Lo único diferente es el registro. La reorganización vuelve a aplicar cambios de una rama de trabajo sobre otra rama, en el mismo orden en que fueron introducidos en la primera. Mientras que la fusión combina entre sí los dos puntos finales de ambas ramas. ### Algunas otras reorganizaciones interesantes ### -También puedes aplicar una reorganización (rebase) sobre otra cosa además de sobre la rama de reorganización. Por ejemplo, sea un registro como el de la Figura 3-31. Has ramificado a una rama puntual ('server') para añadir algunas funcionalidades al proyecto, y luego has confirmado los cambios. Despues, vuelves a la rama original para hacer algunos cambios en la parte cliente (rama 'client'), y confirmas también esos cambios. Por último, vuelves sobre la rama 'server' y haces algunos cambios más. +También puedes aplicar una reorganización (rebase) sobre otra cosa además de sobre la rama de reorganización. Por ejemplo, sea un registro como el de la Figura 3-31. Has ramificado a una rama puntual (`server`) para añadir algunas funcionalidades al proyecto, y luego has confirmado los cambios. Después, vuelves a la rama original para hacer algunos cambios en la parte cliente (rama `client`), y confirmas también esos cambios. Por último, vuelves sobre la rama `server` y haces algunos cambios más. Insert 18333fig0331.png Figura 3-31. Un registro con una rama puntual sobre otra rama puntual. -Imagina que decides incorporar tus cambios de la parte cliente sobre el proyecto principal, para hacer un lanzamiento de versión; pero no quieres lanzar aún los cambios de la parte server porque no están aún suficientemente probados. Puedes coger los cambios del cliente que no estan en server (C8 y C9), y reaplicarlos sobre tu rama principal usando la opción '--onto' del comando 'git rebase': +Imagina que decides incorporar tus cambios de la parte cliente sobre el proyecto principal, para hacer un lanzamiento de versión; pero no quieres lanzar aún los cambios de la parte server porque no están aún suficientemente probados. Puedes coger los cambios del cliente que no están en server (C8 y C9), y reaplicarlos sobre tu rama principal usando la opción `--onto` del comando `git rebase`: $ git rebase --onto master server client -Esto viene a decir: "Activa la rama 'client', averigua los cambios desde el ancestro común entre las ramas 'client' y 'server', y aplicalos en la rama 'master'. Puede parecer un poco complicado, pero los resultados, mostrados en la Figura 3-32, son realmente interesantes. +Esto viene a decir: "Activa la rama `client`, averigua los cambios desde el ancestro común entre las ramas `client` y `server`, y aplicarlos en la rama `master`. Puede parecer un poco complicado, pero los resultados, mostrados en la Figura 3-32, son realmente interesantes. Insert 18333fig0332.png Figura 3-32. Reorganizando una rama puntual fuera de otra rama puntual. @@ -535,23 +535,23 @@ Y, tras esto, ya puedes avanzar la rama principal (ver Figura 3-33): $ git merge client Insert 18333fig0333.png -Figura 3-33. Avance rápido de tu rama 'master', para incluir los cambios de la rama 'client'. +Figura 3-33. Avance rápido de tu rama `master`, para incluir los cambios de la rama `client`. -Ahora supongamos que decides traerlos (pull) también sobre tu rama 'server'. Puedes reorganizar (rebase) la rama 'server' sobre la rama 'master' sin necesidad siquiera de comprobarlo previamente, usando el comando 'git rebase [ramabase] [ramapuntual]'. El cual activa la rama puntual ('server' en este caso) y la aplica sobre la rama base ('master' en este caso): +Ahora supongamos que decides traerlos (pull) también sobre tu rama `server`. Puedes reorganizar (rebase) la rama `server` sobre la rama `master` sin necesidad siquiera de comprobarlo previamente, usando el comando `git rebase [ramabase] [ramapuntual]`. El cual activa la rama puntual (`server` en este caso) y la aplica sobre la rama base (`master` en este caso): $ git rebase master server -Esto vuelca el trabajo de 'server' sobre el de 'master', tal y como se muestra en la Figura 3-34. +Esto vuelca el trabajo de `server` sobre el de `master`, tal y como se muestra en la Figura 3-34. Insert 18333fig0334.png -Figura 3-34. Reorganizando la rama 'server' sobre la rama 'branch'. +Figura 3-34. Reorganizando la rama `server` sobre la rama `branch`. -Después, puedes avanzar rápidamente la rama base ('master'): +Después, puedes avanzar rápidamente la rama base (`master`): $ git checkout master $ git merge server -Y por último puedes eliminar las ramas 'client' y 'server' porque ya todo su contenido ha sido integrado y no las vas a necesitar más. Dejando tu registro tras todo este proceso tal y como se muestra en la Figura 3-35: +Y por último puedes eliminar las ramas `client` y `server` porque ya todo su contenido ha sido integrado y no las vas a necesitar más. Dejando tu registro tras todo este proceso tal y como se muestra en la Figura 3-35: $ git branch -d client $ git branch -d server @@ -561,15 +561,15 @@ Figura 3-35. Registro final de confirmaciones de cambio. ### Los peligros de la reorganización ### -Ahh...., pero la dicha de la reorganización no la alcanzamos sin sus contrapartidas: +Ahh..., pero la dicha de la reorganización no la alcanzamos sin sus contrapartidas: **Nunca reorganices confirmaciones de cambio (commits) que hayas enviado (push) a un repositorio público.** Siguiendo esta recomendación, no tendrás problemas. Pero si no la sigues, la gente te odiará y serás despreciado por tus familiares y amigos. -Cuando reorganizas algo, estás abandonando las confirmaciones de cambio ya creadas y estás creando unas nuevas; que son similares, pero diferentes. Si envias (push) confirmaciones (commits) a alguna parte, y otros las recogen (pull) de allí. Y después vas tu y las reescribes con 'git rebase' y las vuelves a enviar (push) de nuevo. Tus colaboradores tendrán que refusionar (re-merge) su trabajo y todo se volverá tremendamente complicado cuando intentes recoger (pull) su trabajo de vuelta sobre el tuyo. +Cuando reorganizas algo, estás abandonando las confirmaciones de cambio ya creadas y estás creando unas nuevas; que son similares, pero diferentes. Si envias (push) confirmaciones (commits) a alguna parte, y otros las recogen (pull) de allí. Y después vas tu y las reescribes con `git rebase` y las vuelves a enviar (push) de nuevo. Tus colaboradores tendrán que refusionar (re-merge) su trabajo y todo se volverá tremendamente complicado cuando intentes recoger (pull) su trabajo de vuelta sobre el tuyo. -Vamos a verlo con un ejemplo. Imaginate que haces un clon desde un servidor central, y luego trabajas sobre él. Tu registro de cambios puede ser algo como lo de la Figura 3-36. +Vamos a verlo con un ejemplo. Imagínate que haces un clon desde un servidor central, y luego trabajas sobre él. Tu registro de cambios puede ser algo como lo de la Figura 3-36. Insert 18333fig0336.png Figura 3-36. Clonar un repositorio y trabajar sobre él. @@ -579,20 +579,20 @@ Ahora, otra persona trabaja también sobre ello, realiza una fusión (merge) y l Insert 18333fig0337.png Figura 3-37. Traer (fetch) algunas confirmaciones de cambio (commits) y fusionarlas (merge) sobre tu trabajo. -A continuación, la persona que habia llevado cambios al servidor central decide retroceder y reorganizar su trabajo; haciendo un 'git push --force' para sobreescribir el registro en el servidor. Tu te traes (fetch) esos nuevos cambios desde el servidor. +A continuación, la persona que había llevado cambios al servidor central decide retroceder y reorganizar su trabajo; haciendo un `git push --force` para sobrescribir el registro en el servidor. Tu te traes (fetch) esos nuevos cambios desde el servidor. Insert 18333fig0338.png -Figura 3-38. Alguien envia (push) confirmaciones (commits) reorganizadas, abandonando las confirmaciones en las que tu habias basado tu trabajo. +Figura 3-38. Alguien envií (push) confirmaciones (commits) reorganizadas, abandonando las confirmaciones en las que tu habías basado tu trabajo. En ese momento, tu te ves obligado a fusionar (merge) tu trabajo de nuevo, aunque creias que ya lo habias hecho antes. La reorganización cambia los resumenes (hash) SHA-1 de esas confirmaciones (commits), haciendo que Git se crea que son nuevas confirmaciones. Cuando realmente tu ya tenias el trabajo de C4 en tu registro. Insert 18333fig0339.png Figura 3-39. Vuelves a fusionar el mismo trabajo en una nueva fusión confirmada. -Te ves obligado a fusionar (merge) ese trabajo en algún punto, para poder seguir adelante con otros desarrollos en el futuro. Tras todo esto, tu registro de confirmaciones de cambio (commit history) contendrá tanto la confirmación C4 como la C4'; teniendo ambas el mismo contenido y el mismo mensaje de confirmación. Si lanzas un 'git log' en un registro como este, verás dos confirmaciones con el mismo autor, misma fecha y mismo mensaje. Lo que puede llevar a confusiones. Es más, si luego tu envias (push) ese registro de vuelta al servidor, vas a introducir todas esas confirmaciones reorganizadas en el servidor central. Lo que puede confundir aún más a la gente. +Te ves obligado a fusionar (merge) ese trabajo en algún punto, para poder seguir adelante con otros desarrollos en el futuro. Tras todo esto, tu registro de confirmaciones de cambio (commit history) contendrá tanto la confirmación C4 como la C4'; teniendo ambas el mismo contenido y el mismo mensaje de confirmación. Si lanzas un `git log` en un registro como este, verás dos confirmaciones con el mismo autor, misma fecha y mismo mensaje. Lo que puede llevar a confusiones. Es más, si luego tu envías (push) ese registro de vuelta al servidor, vas a introducir todas esas confirmaciones reorganizadas en el servidor central. Lo que puede confundir aún más a la gente. Si solo usas la reorganización como una vía para hacer limpieza y organizar confirmaciones de cambio antes de enviarlas, y si únicamente reorganizas confirmaciones que nunca han sido públicas. Entonces no tendrás problemas. Si, por el contrario, reorganizas confirmaciones que alguna vez han sido públicas y otra gente ha basado su trabajo en ellas. Entonces estarás en un aprieto. ## Recapitulación ## -Hemos visto los procedimientos básicos de ramificación (branching) y fusión (merging) en Git. A estas alturas, te sentirás cómodo creando nuevas ramas (branch), saltando (checkout) entre ramas para trabajar y fusionando (merge) ramas entre ellas. También conocerás cómo compatir tus ramas enviandolas (push) a un servidor compartido, cómo trabajar colaborativamente en ramas compartidas, y cómo reorganizar (rebase) tus ramas antes de compartirlas. +Hemos visto los procedimientos básicos de ramificación (branching) y fusión (merging) en Git. A estas alturas, te sentirás cómodo creando nuevas ramas (branch), saltando (checkout) entre ramas para trabajar y fusionando (merge) ramas entre ellas. También conocerás cómo compartir tus ramas enviándolas (push) a un servidor compartido, cómo trabajar colaborativamente en ramas compartidas, y cómo reorganizar (rebase) tus ramas antes de compartirlas. diff --git a/es/04-git-server/01-chapter4.markdown b/es/04-git-server/01-chapter4.markdown index 4cc8612a3..b9fde505d 100755 --- a/es/04-git-server/01-chapter4.markdown +++ b/es/04-git-server/01-chapter4.markdown @@ -68,7 +68,7 @@ El aspecto negativo de SSH es su imposibilidad para dar acceso anónimo al repos ### El Protocolo Git ### -El protocolo Git es un demonio (daemon) especial, que viene incorporado con Git. Escucha por un puerto dedicado (9418), y nos da un servicio similar al del protocolo SSH; pero sin ningún tipo de autentificación. Para que un repositorio pueda exponerse a través del protocolo Git, tienes que crear en él un archivo 'git-export-daemon-ok'; sin este archivo, el demonio no hará disponible el repositorio. Pero, aparte de esto, no hay ninguna otra medida de seguridad. O el repositorio está disponible para que cualquiera lo pueda clonar, o no lo está. Lo cual significa que, normalmente, no se podrá enviar (push) a través de este protocolo. Aunque realmente si que puedes habilitar el envio, si lo haces, dada la total falta de ningún mecanismo de autentificación, cualquiera que encuentre la URL a tu proyecto en Internet, podrá enviar (push) contenidos a él. Ni que decir tiene que esto solo lo necesitarás en contadas ocasiones. +El protocolo Git es un demonio (daemon) especial, que viene incorporado con Git. Escucha por un puerto dedicado (9418), y nos da un servicio similar al del protocolo SSH; pero sin ningún tipo de autentificación. Para que un repositorio pueda exponerse a través del protocolo Git, tienes que crear en él un archivo 'git-daemon-export-ok'; sin este archivo, el demonio no hará disponible el repositorio. Pero, aparte de esto, no hay ninguna otra medida de seguridad. O el repositorio está disponible para que cualquiera lo pueda clonar, o no lo está. Lo cual significa que, normalmente, no se podrá enviar (push) a través de este protocolo. Aunque realmente si que puedes habilitar el envio, si lo haces, dada la total falta de ningún mecanismo de autentificación, cualquiera que encuentre la URL a tu proyecto en Internet, podrá enviar (push) contenidos a él. Ni que decir tiene que esto solo lo necesitarás en contadas ocasiones. ### Ventajas ### @@ -361,13 +361,13 @@ En este punto, es posible que desees cambiar a un popular programa llamado Gitos Instalar Gitosis no es precisamente sencillo. Pero tampoco demasiado complicado. Es más sencillo hacerlo si utilizas un servidor Linux --estos ejemplos se han hecho sobre un servidor Ubuntu 8.10--. -Gitosis necesita de ciertas herramientas Python, por lo que la primera tarea será instalar el paquete de herramientas Pyton. En Ubuntu viene como el paquete python-stuptools: +Gitosis necesita de ciertas herramientas Python, por lo que la primera tarea será instalar el paquete de herramientas Pyton. En Ubuntu viene como el paquete python-setuptools: - $ apt-get install python-setuptools + $ sudo apt-get install python-setuptools A continuación, has de clonar e instalar Gitosis desde el repositorio principal de su proyecto: - $ git clone git://eagain.net/gitosis.git + $ git clone https://github.com/tv42/gitosis.git $ cd gitosis $ sudo python setup.py install @@ -404,9 +404,8 @@ Y ya estás preparado para trabajar. Si lo has configurado todo correctamente, p fatal: unrecognized command 'gitosis-serve schacon@quaternion' Connection to gitserver closed. -Indicandote que Gitosis te ha reconocido, pero te está hechando debido a que no estás intentando lanzar ningún comando Git. Por tanto, intentalo con un comando Git real --por ejemplo, clonar el propio repositorio de control de Gitosis - - a tu ordenador personal-- +Indicandote que Gitosis te ha reconocido, pero te está hechando debido a que no estás intentando lanzar ningún comando Git. Por tanto, intentalo con un comando Git real --por ejemplo, clonar el propio repositorio de control de Gitosis a tu ordenador personal-- + $ git clone git@gitserver:gitosis-admin.git Con ello, tendrás una carpeta denominada 'gitosis-admin', con dos partes principales dentro de ella: @@ -585,7 +584,7 @@ GitHub es también una compañia comercial, que cobra por las cuentas que tienen ### Configurando una cuenta de usuario ### -El primer paso es dar de alta una cuenta gratuita. Si visitas la página de Precios e Inicio de Sesión, en 'http://github.com/plans', y clicas sobre el botón "Registro" ("Sign Up") de las cuentas gratuitas, verás una página de registro: +El primer paso es dar de alta una cuenta gratuita. Si visitas la página de Precios e Inicio de Sesión, en 'https://github.com/pricing', y clicas sobre el botón "Registro" ("Sign Up") de las cuentas gratuitas, verás una página de registro: Insert 18333fig0402.png Figura 4-2. La página de planes GitHub. diff --git a/es/05-distributed-git/01-chapter5.markdown b/es/05-distributed-git/01-chapter5.markdown index 2f4f74e7e..083205c9a 100644 --- a/es/05-distributed-git/01-chapter5.markdown +++ b/es/05-distributed-git/01-chapter5.markdown @@ -1,6 +1,6 @@ # Git en entornos distribuidos # -Ahora que ya tienes un repositorio Git, configurado como punto de trabajo para compartir código entre desarrolladores. Y ahora que ya conoces los comandos básicos de Git para flujos de trabajo locales. Puedes hechar un vistazo a algunos de los flujos de trabajo distribuidos que Git permite. +Ahora que ya tienes un repositorio Git, configurado como punto de trabajo para compartir código entre desarrolladores. Y ahora que ya conoces los comandos básicos de Git para flujos de trabajo locales. Puedes echar un vistazo a algunos de los flujos de trabajo distribuidos que Git permite. En este capítulo, verás cómo trabajar con Git en un entorno distribuido, bien como colaborador o bien como integrador. Es decir, aprenderás cómo contribuir adecuadamente a un proyecto; de la forma más efectiva posible, tanto para tí, como para quien gestione el proyecto. Y aprenderás también a gestionar proyectos en los que colaboren multiples desarrolladores. @@ -27,7 +27,7 @@ Al permitir multiples repositorios remotos, en Git es posible tener un flujo de 1. La persona gestora del proyecto envia (push) a su repositorio público (repositorio principal). 2. Una persona que desea contribuir, clona dicho repositorio y hace algunos cambios. 3. La persona colaboradora envia (push) a su propia copia pública. -4. Esta persona colaboradora envia a la gestora un correo-e solicitándole recupere e integre los cambios. +4. Esta persona colaboradora envia a la gestora un correo electronico solicitándole recupere e integre los cambios. 5. La gestora añade como remoto el repositorio de la colaboradora y fusiona (merge) los cambios localmente. 6. La gestora envia (push) los cambios fusionados al repositorio principal. @@ -299,7 +299,7 @@ Quedando su repositorio como se muestra en la Figura 5-12 Insert 18333fig0512.png Figura 5-12. Historial inicial de Jessica. -Cuando está preparada para enviar (push) su trabajo, recibe un correo-e de Josie de que ha puesto en el servidor una rama denominada 'featureBee', con algo de trabajo. Jessica necesita fusionar (merge) dichos cambios con los suyos antes de poder enviarlos al servidor. Por tanto, recupera (fetch) los cambios de Josie: +Cuando está preparada para enviar (push) su trabajo, recibe un correo electronico de Josie de que ha puesto en el servidor una rama denominada 'featureBee', con algo de trabajo. Jessica necesita fusionar (merge) dichos cambios con los suyos antes de poder enviarlos al servidor. Por tanto, recupera (fetch) los cambios de Josie: $ git fetch origin ... @@ -323,7 +323,7 @@ Pero hay un pequeño problema, necesita enviar el trabajo fusionado en su rama ' Esto es lo que se denomina un _refspec_. Puedes ver el Capítulo 9 para una discusión más detallada acerca de los _refspecs_ de Git y los distintos usos que puedes darles. -A continuación, John envia un correo-e a jessica comentandole que ha enviado algunos cambios a la rama 'featureA' y pidiendole que los verifique. Ella lanza un 'git fetch' para recuperar dichos cambios: +A continuación, John envia un correo electronico a jessica comentandole que ha enviado algunos cambios a la rama 'featureA' y pidiendole que los verifique. Ella lanza un 'git fetch' para recuperar dichos cambios: $ git fetch origin ... @@ -560,7 +560,7 @@ En esta sección hemos visto unos cuantos de los flujos de trabajo más habitual ## Gestionando un proyecto ## -Además de conocer cómo contribuir de forma efectiva a un proyecto, es posible que desees saber tambien cómo mantener uno. Lo cual implicará saber aceptar y aplicar parches generados vía `format-patch`, enviados a tí a través de correo-e; o saber integrar cambios realizados en ramas de repositorios que añadirás como remotos a tu proyecto. Tanto si gestionas un repositorio canónico, como si deseas colaborar verificando o aprobando parches, necesitas saber cómo aceptar trabajo de otros de la forma más clara para tus contribuyentes y más sostenible para tí a largo plazo. +Además de conocer cómo contribuir de forma efectiva a un proyecto, es posible que desees saber tambien cómo mantener uno. Lo cual implicará saber aceptar y aplicar parches generados vía `format-patch`, enviados a tí a través de correo electronico; o saber integrar cambios realizados en ramas de repositorios que añadirás como remotos a tu proyecto. Tanto si gestionas un repositorio canónico, como si deseas colaborar verificando o aprobando parches, necesitas saber cómo aceptar trabajo de otros de la forma más clara para tus contribuyentes y más sostenible para tí a largo plazo. ### Trabajando con Ramas Puntuales ### @@ -575,9 +575,9 @@ O, si deseas crearla y saltar inmediatamente a ella, puedes también utilizar la Tras esto, estarás listo para añadir tu trabajo a esa rama puntual y ver si deseas o no fusionarla luego con alguna otra de tus ramas de más largo recorrido. -### Aplicar parches recibidos por correo-e ### +### Aplicar parches recibidos por correo electronico ### -Si vas a integrar en tu proyecto un parche recibido a través de un correo electrónico. Antes de poder evaluarlo, tendrás que incorporarlo a una de tus ramas puntuales. Tienes dos caminos para incorporar un parche recibido por correo-e: usando el comando 'git apply' o usando el comando 'git am'. +Si vas a integrar en tu proyecto un parche recibido a través de un correo electrónico. Antes de poder evaluarlo, tendrás que incorporarlo a una de tus ramas puntuales. Tienes dos caminos para incorporar un parche recibido por correo electronico: usando el comando 'git apply' o usando el comando 'git am'. #### Incorporando un parche con apply #### @@ -683,9 +683,9 @@ Por ejemplo, si Jessica te envia un correo electrónico comentandote que tiene u $ git fetch jessica $ git checkout -b rubyclient jessica/ruby-client -Si más tarde vuelva a enviarte otro correo-e avisandote de otra gran funcionalidad que ha incorporado, puedes recuperarla (fetch y checkout) directamente, porque tienes el remoto ya definido. +Si más tarde vuelva a enviarte otro correo electronico avisandote de otra gran funcionalidad que ha incorporado, puedes recuperarla (fetch y checkout) directamente, porque tienes el remoto ya definido. -Es muy util cuando trabajas regularmente con una persona. En cambio, si alguien tiene un solo parche para enviarte, una sola vez, puede ser más efectivo aceptarlo directamente por correo-e; en lugar de pedir a todo el mundo que tenga cada uno su propio servidor y tener nosotros que estar continuamente añadiendo y quitando remotos para cada parche. También es muy posible que no quieras tener cientos de remotos, cada uno contribuyendo tan solo con un parche o dos. De todas formas, los scripts y los servicios albergados pueden hacerte la vida más facil en esto, --todo depende de cómo desarrolles tú y de como desarrollan las personas que colaboran contigo--. +Es muy util cuando trabajas regularmente con una persona. En cambio, si alguien tiene un solo parche para enviarte, una sola vez, puede ser más efectivo aceptarlo directamente por correo electronico; en lugar de pedir a todo el mundo que tenga cada uno su propio servidor y tener nosotros que estar continuamente añadiendo y quitando remotos para cada parche. También es muy posible que no quieras tener cientos de remotos, cada uno contribuyendo tan solo con un parche o dos. De todas formas, los scripts y los servicios albergados pueden hacerte la vida más facil en esto, --todo depende de cómo desarrolles tú y de como desarrollan las personas que colaboran contigo--. Otra ventaja de esta forma de trabajar es que recibes también el histórico de confirmaciones de cambio (commits). A pesar de poder seguir teniendo los habituales problemas con la fusión, por lo menos conoces en qué punto de tu historial han basado su trabajo. Por defecto, se aplicará una genuina fusión a tres bandas, en lugar de tener que poner un '-3' y esperar que el parche haya sido generado a partir de una confirmación de cambios (commit) pública a la que tengas tú también acceso. diff --git a/es/06-git-tools/01-chapter6.markdown b/es/06-git-tools/01-chapter6.markdown index 254a8656f..5ae5c5c8b 100644 --- a/es/06-git-tools/01-chapter6.markdown +++ b/es/06-git-tools/01-chapter6.markdown @@ -59,7 +59,7 @@ Mucha gente se suele preocupar por si, por casualidad, dos objetos en su reposit Si se da la casualidad de confirmar cambios en un objeto y que a este se le asigne el mismo código SHA-1 que otro ya existente en el repositorio. Al ver el objeto previamente almacenado en la base de datos, Git asumirá que este ya existía. Al intentar recuperar (check-out) el objeto más tarde, siempre se obtendrán los datos del primer objeto. -No obstante, hemos de ser conscientes de lo altamente improbable de un suceso así. Los códigos SHA-1 son de 20 bytes, (160 bits). El número de objetos, codificados aleatóriamente, necesarios para asegurar un 50% de probabilidad de darse una sola colisión es cercano a 2^80 (la fórmula para determinar la probabilidad de colisión es `p = (n(n-1)/2) * (1/2^160))`). 2^80 es 1'2 x 10^24, o lo que es lo mismo, 1 billón de billones. Es decir, unas 1.200 veces el número de granos de arena en la Tierra. +No obstante, hemos de ser conscientes de lo altamente improbable de un suceso así. Los códigos SHA-1 son de 20 bytes, (160 bits). El número de objetos, codificados aleatóriamente, necesarios para asegurar un 50% de probabilidad de darse una sola colisión es cercano a 2^80 (la fórmula para determinar la probabilidad de colisión es `p = (n(n-1)/2) * (1/2^160)`)). 2^80 es 1'2 x 10^24, o lo que es lo mismo, 1 billón de billones. Es decir, unas 1.200 veces el número de granos de arena en la Tierra. El siguiente ejemplo puede ser bastante ilustrativo, para hacernos una idea de lo que podría tardarse en darse una colisión en el código SHA-1: Si todos los 6'5 billones de humanos en el planeta Tierra estuvieran programando y, cada segundo, cada uno de ellos escribiera código equivalente a todo el histórico del kernel de Linux (cerca de 1 millón de objetos Git), enviandolo todo a un enorme repositorio Git. Serían necesarios unos 5 años antes de que dicho repositorio contuviera suficientes objetos como para tener una probabilidad del 50% de darse una sola colisión en el código SHA-1. Es mucho más probable que todos los miembros de nuestro equipo de programación fuesen atacados y matados por lobos, en incidentes no relacionados entre sí, acaecidos todos ellos en una misma noche. @@ -440,7 +440,7 @@ Con ello, se limpia el área de trabajo: $ git status # On branch master - nothing to commit (working directory clean) + nothing to commit, working directory clean Y se permite cambiar de rama para ponerse a trabajar en cualquier otra parte. Con la tranquilidad de que los cambios a medio completar están guardados a buen recaudo en la pila de guardado rápido. Para ver el contenido de dicha pila, se emplea el comando 'git stash list': diff --git a/es/07-customizing-git/01-chapter7.markdown b/es/07-customizing-git/01-chapter7.markdown index af19b3cc6..6ac5413f4 100644 --- a/es/07-customizing-git/01-chapter7.markdown +++ b/es/07-customizing-git/01-chapter7.markdown @@ -142,7 +142,7 @@ Si lo quieres probar, P4Merge funciona en todas las principales plataformas. Los P4Merge se puede descargar desde: - http://www.perforce.com/perforce/downloads/component.html + http://www.perforce.com/product/components/perforce-visual-merge-and-diff-tools Para empezar, tienes que preparar los correspondientes scripts para lanzar tus comandos. En estos ejemplos, voy a utilizar caminos y nombres Mac para los ejecutables; en otros sistemas, tendrás que sustituirlos por los correspondientes donde tengas instalado 'p4merge'. El primer script a preparar es uno al que denominaremos 'extMerge', para llamar al ejecutable con los correspodientes argumentos: diff --git a/es/08-git-and-other-scms/01-chapter8.markdown b/es/08-git-and-other-scms/01-chapter8.markdown index 981a56d40..8df7dc775 100644 --- a/es/08-git-and-other-scms/01-chapter8.markdown +++ b/es/08-git-and-other-scms/01-chapter8.markdown @@ -598,7 +598,7 @@ The last thing you need to do is to return the current mark so it can be passed return mark -NOTE: If you are running on Windows you'll need to make sure that you add one extra step. As metioned before, Windows uses CRLF for new line characters while git fast-import expects only LF. To get around this problem and make git fast-import happy, you need to tell ruby to use LF instead of CRLF: +NOTE: If you are running on Windows you'll need to make sure that you add one extra step. As mentioned before, Windows uses CRLF for new line characters while git fast-import expects only LF. To get around this problem and make git fast-import happy, you need to tell ruby to use LF instead of CRLF: $stdout.binmode diff --git a/es/omegat-Benzirpi.tmx b/es/omegat-Benzirpi.tmx index f2e101c15..95f49f3b2 100644 --- a/es/omegat-Benzirpi.tmx +++ b/es/omegat-Benzirpi.tmx @@ -2369,10 +2369,10 @@ Figura 3-36. - http://www.perforce.com/perforce/downloads/component.html + http://www.perforce.com/product/components/perforce-visual-merge-and-diff-tools - http://www.perforce.com/perforce/downloads/component.html + http://www.perforce.com/product/components/perforce-visual-merge-and-diff-tools @@ -7133,12 +7133,12 @@ Figura 5-2. - $ git clone git://eagain.net/gitosis.git + $ git clone https://github.com/tv42/gitosis.git $ cd gitosis $ sudo python setup.py install - $ git clone git://eagain.net/gitosis.git + $ git clone https://github.com/tv42/gitosis.git $ cd gitosis $ sudo python setup.py install @@ -28305,12 +28305,12 @@ Figura 5-21. $ git status # On branch master - nothing to commit (working directory clean) + nothing to commit, working directory clean $ git status # On branch master - nothing to commit (working directory clean) + nothing to commit, working directory clean diff --git a/fa/.gitignore b/fa/.gitignore new file mode 100644 index 000000000..b7cd94167 --- /dev/null +++ b/fa/.gitignore @@ -0,0 +1,2 @@ +.DS_store +.idea \ No newline at end of file diff --git a/fa/01-introduction/01-chapter1.markdown b/fa/01-introduction/01-chapter1.markdown new file mode 100644 index 000000000..f259f012f --- /dev/null +++ b/fa/01-introduction/01-chapter1.markdown @@ -0,0 +1,262 @@ +# سرآغاز # + +در این فصل در رابطه با شروع کار با Git صحبت خواهد شد. این فصل با توضیحاتی در رابطه با تاریخچه ابزارهای کنترل نسخه شروع می‌شود، سپس چگونگی راه اندازی Git برروی یک سیستم خاص آموزش داده خواهد شد و در انتها انجام تنظیمات موردنیاز برروی این نرم افزار جهت شروع به کار با آن مورد بررسی قرار می‌گیرد. در انتهای این فصل خواننده باید دلیل وجود و استفاده از Git را بداند و همچنین باید محیط کار را برای استفاده از آن فراهم کرده باشد. + +## کنترل نسخه ## + +کنترل نسخه چیست و چه اهمیتی دارد؟ کنترل نسخه سیستمی است که تغییرات مربوط به یک یا چندین فایل را در طول زمان ذخیره می‌کند، تا کاربر بتواند به نسخه‌های قبلی مراجعت داشته باشد. در مثال‌های استفاده شده در این کتاب از فایل های سورس نرم افزار جهت نمایش کنترل نسخه استفاده می‌شود، ولی با این وجود می‌توان هر نوع فایلی را تحت کنترل نسخه قرار داد. + +اگر شما یک گرافیست یا طراح وب باشید و تصمیم به نگهداری تمامی نسخه‌های یک عکس یا ساختار را داشته باشید (که قطعًا به همین منوال است)، استفاده از یک سیستم کنترل نسخه (VCS) راهبردی عاقلانه است. یک VCS این امکان را به شما می‌دهد تا: فایل‌ها یا پروژه‌ای را به یک وضعیت قبل برگردانید، تغییرات انجام گرفته در مرور زمان را مشاهده کنید، باعث و بانی تغییری را که منجر به ایجاد خطا یا مشکلی در سیستم شده است بیابید، چه کسی و چه زمانی موردی خاص را مطرح کرده است و بسیاری موارد دیگر. استفاده از یک VCS حتی این امکان را به شما می‌دهد که اگر احیاناً خطایی مرتکب شدید یا فایلی را اشتباهاً حذف یا از دست دادید، به راحتی آن را اصلاح و بازیابی کنید. + +### سیستمهای کنترل نسخه محلی ### + +روشی که اکثر کاربران جهت کنترل نسخه انتخاب می‌کنند شامل کپی کردن فایل‌ها در پوشه‌های دیگر است (البته اگر هوشمندی نشان دهند، پوشه موردنظر را با تاریخ و زمان مشخصی نامگذاری می‌کنند). چنین روشی به جهت سادگی بین کاربران بسیار رایج است، ولی خطاپذیری بالایی نیز دارد. در این روش امکان دارد فرد به آسانی پوشه‌ای که در آن قرار دارد را فراموش کرده و به اشتباه دست به تغییر فایل‌هایی بزند که مدنظر او نیست. + +برای مقابله با این موذل، برنامه نویسان از زمان‌های بسیار قبل اقدام به توسعه VCSها زده‌اند که در بردارنده پایگاه داده ساده‌ای هستند به گونه ای که تمامی تغییرات انجام شده برروی فایل‌های هدف را در قالب کنترل نسخه نگهداری می‌کنند (تصویر 1-1) + +Insert 18333fig0101.png +تصویر 1-1. دیاگرام کنترل نسخه محلی. + +یکی از رایجترین ابزارهای VCS سیستمی با نام rcs بوده است، که هم اکنون نیز به همراه تعداد زیادی از کامپیوترهای امروزی نیز توزیع می‌شود. حتی سیستم عامل رایج Mac OS X نیز با نصب ابزارهای توسعه توسط کاربر برروی آن، دستور خط فرمان rcs را در اختیار فرد قرار می‌دهد. این ابزار به زبانی ساده با حفظ مجموعه‌ای از وصله‌ها (که تغییرات بین فایل‌ها می‌باشند) از یک نسخه به نسخه‌ای دیگر در قالب فرمتی خاص برروی دیسک عمل می‌کند؛ این ابزار با اجرای چنین سیستمی قادر است با متصل کردن وصله‌ها به یکدیگر توانایی بازسازی هر فایلی را در هر لحظه‌ای از زمان داشته باشد. + +### سیستمهای کنترل نسخه‌ مرکزی ### + +مسئله مهم دیگری که کاربران با آن مواجه می‌شوند، نیاز آن‌ها به همکاری با دیگر توسعه‌دهندگان برروی سیستم‌های دیگر است. برای حل این مسئله، سیستم‌های کنترل نسخه مرکزی (CVCSs) توسعه یافتند. چنین سیستم‌هایی مانند CVS، Subversion و Perforce در بردارنده سروری مرکزی هستند که تمامی نسخه‌های فایل‌ها و حتی کاربرانی که این فایل‌ها را از این مکان مرکزی checkout کرده‌اند در خود نگهداری می‌کند. برای سال‌های زیادی، چنین روشی، روشی استاندارد برای کنترل نسخه بوده است (تصویر 1-2). + +Insert 18333fig0102.png +تصویر 1-2. دیاگرام کنترل نسخه مرکزی. + +این ساختار مزایای بسیاری مخصوصاً نسبت به سیستم‌های کنترل نسخه محلی دارد. به عنوان مثال، هر فرد در حد و اندازه مشخصی خواهد توانست بداند که دیگر افراد تا چه اندازه در پروژه شریک هستند. مدیران از این نظر که هرکس از نظر سطح دسترسی قادر به انجام چه کاری است، کنترل مناسبی دارند؛ همچنین مدیریت یک CVCS به مراتب آسانتر از تعامل با پایگاه‌های داده محلی موجود برروی سیستم‌های کاربران است. + +با این وجود، چنین ساختاری معایبی نیز دارد. واضح‌ترین موضوع بروز کوچکترین ایراد در سرورهای مرکزی است. اگر برای مدت یک ساعت این سرور متوقف و از کار بیفتد، در طی این بازه یک ساعته هیچکس نخواهد توانست تعاملی با سرور داشته باشد یا حتی تغییرات نسخه را برروی چیزی که در حال کارکردن با آن است ذخیره کند. اگر هارد دیسکی که پایگاه داده مرکزی برروی آن قرار دارد خراب شود، و پشتیبان مناسبی از آن گرفته نشده باشد، کاربر به طور کامل تاریخچه پروژه را از دست خواهد داد به جز تصاویر لحظه‌ای که هر کاربر احتمالاً برروی ماشین محلی خود خواهد داشت. سیستمهای VCS محلی نیز این عیب را به ارث می‌برند-اگر کاربر تمامی تاریخچه پروژه را در یک مکان ذخیره کند، ریسک از دادن همه چیز به قوت خود باقی خواهد ماند. + +### سیستمهای کنترل نسخه پخشی ### + +اینجا است که سیستم‌های کنترل نسخه پخشی (DVCSs) نمود پیدا می‌کنند. در یک DVCS (مانند Git، Mercurial، Bazaar یا Darcs) کابران به checkout کردن آخرین تصویر لحظه‌ای فایل‌ها اکتفا نمی‌کنند: آن‌ها مخزن را نیز به‌صورت کامل کپی می‌کنند. بنابراین اگر هر سروری که سیستم‌ها به واسطه آن در حال تعامل با یکدیگر هستند متوقف و از کار بیافتد، با کپی مخرن هر کدام از کاربران برروی سرور، عمل بازیابی انجام می‌گیرد. در واقع هر checkoutای، پشتیبان کاملی از تمامی داده‌ها است. + +Insert 18333fig0103.png +تصویر 1-3. دیاگرام کنترل نسخه پخشی. + +علاوه بر آن اکثر این سیستم‌ها تعامل خوبی با داشتن مخازن خارجی متعدد جهت کار کردن با آن‌ها دارند، در نتیجه شخص خواهد توانست با گروه‌های مختلفی در قالب پروژه‌ای یکسان به‌صورت همزمان تعامل داشته باشد. این قابلیت این امکان را به کاربر خواهد داد که جریان‌های کاری متنوعی همانند مدل‌های سلسه مراتبی را پیاده سازی کند که انجام آن در سیستم‌های متمرکز امکان پذیر نیست. + +## تاریخچه کوتاهی از Git ## + +همانند اکثر حوادث بزرگ در در زندگی، Git نیز با خلاقیتی مخرب و جنجالی آتشین شروع شد. هسته لینوکس پروژه نرم‌افزاری متن باز با وسعت نسبتاً زیادی است. جهت نگهداری هسته لینوکس برای مدت زمان زیادی (1991 - 2002) تغییرات نرم‌افزاری به واسطه وصله‌ها و فایل‌های بایگانی شده انتقال پیدا می‌کرد. در سال 2002، پروژه هسته لینوکس شروع به استفاده از سیستم DVCS خصوصی با نام BitKeeper کرد. + +در سال 2005، ارتباط بین مجموعه تیم توسعه دهنده هسته لینوکس و شرکت تجاری توسعه دهنده BitKeeper گسسته شد و وضعیت ابزاری که قبل از آن به صورت رایگان عرضه می‌گشت تغییر پیدا کرد. این اتفاق زنگ هشداری برای مجموعه تیم توسعه دهنده لینوکس (به خصوص مؤسس لینوکس، لینوس تورلوادز) بود که بر اساس تجربه‌های کسب شده در استفاده از BitKeeper، خود اقدام به تولید نرم افزاری در این زمینه بزنند. مواردی از اهداف سیستم جدید عبارت بودند از: + +* سرعت +* طراحی ساده +* پشتیبانی قوی از توسعه غیر خطی (هزاران انشعاب موازی) +* کاملاً پخشی +* قابلیت کنترل بهینه پروژه‌های بزرگ همانند هسته لینوکس (از نظر سرعت و اندازه داده) + +از زمان تولد Git در سال 2005، این نرم افزار از نظر استفاده آسان و حفظ اهداف اولیه ذکر شده به تکامل و بلوغ رسیده است. Git نرم افزاری سریع، بسیار بهینه در مواجه با پروژه‌های بزرگ و حاوی سیستم انشعابی باورنکردنی برای توسعه غیر خطی است (فصل 3). + +## مقدمات Git ## + +خوب، Git چیست؟ این بخش از نظر یادگیری، بخشی مهم قلمداد می شود، زیرا اگر فرد از پایه و اساس عملکرد Git اطلاع پیدا کند، آنگاه خواهد توانست آسان‌تر در استفاده مؤثر از آن بهره جوید. در حین یادگیری Git، بهتر است فرد ذهن خود را از مواردی که احیاناً در رابطه با دیگر VCSها همانند Subversion و Perforce می‌داند تخلیه کند؛ بدین سبب از بروز اشتباهات موردی در استفاده از این ابزار پیشگیری می‌شود. با وجود آن‌که رابط کاربری Git نسبتاً مشابه با دیگر سیستم‌ها است، ولی در ذخیره سازی و نگاه به اطلاعات، دید بسیار متفاوتی در مقایسه با دیگر سیستم‌ها دارد؛ دانستن این تفاوت‌ها می‌تواند به فرد در جلوگیری از بروز اشتباهات بعدی در استفاده از این ابزار یاری دهد. + +### تصاویر لحظه‌ای، نه تفاوتها ### + +اصلی‌ترین تفاوت بین Git و دیگر VCSها (که شامل Subversion و هم خانواده های آن نیز می‌شود) دیدگاهی است که Git نسبت به داده‌های خود دارد. از نظر مفهومی، اکثریت دیگر سیستم‌ها اطلاعات را به مثابه لیستی از تغییرات بر مبنای فایل، ذخیره می‌کنند. این سیستم‌ها (CVS، Subversion، Perfoce، Bazaar و غیره) همان‌طور که در تصویر 1-4 نشان داده شده است، به اطلاعاتی که نگهداری می‌کنند به شکل مجموعه‌ای از فایل‌ها و تغییراتی که برروی هر فایل در مرور زمان انجام گرفته است، می‌نگرند. + + +Insert 18333fig0104.png +تصویر 1-4. دیگر سیستم‌ها داده‌ها به شکل تغییرات در نسخه پایه هر فایل ذخیره می‌کنند. + +سGit از چنین تفکر یا روش ذخیره سازی داده‌ای پیروی نمی‌کند. در عوض دیدگاه Git نسبت به داده‌های خود به شکل تصاویر لحظه‌ای از یک سیستم فایلی کوچک است. هر زمانی که شخص commitای انجام می‌دهد یا وضعیت پروژه خود را در Git ذخیره می‌کند، در اصل تصویری از وضعیت تمامی فایل‌ها در لحظه موردنظر تهیه و ارجاعی به تصویر لحظه‌ای ایجاد شده ذخیره می شود. برای آن‌که این عمل به صورت بهینه انجام پذیرد، اگر در فایلی تغییری ایجاد نشده باشد، Git اقدام به ذخیره سازی مجدد فایل نمی‌کند - تنها پیوندی به نسخه مشابه آن فایل که قبلاً ذخیره شده است را ذخیره می کند. طریقه نگرش Git به داده در تصویر 1-5 نمایش داده شده است. + +Insert 18333fig0105.png +تصویر 1-5. Git داده‌ها را به شکل تصاویر لحظه‌ای از پروژه در مرور زمان نگهداری می‌کند. + +این شکل نگرش مهمترین اصل تمایز Git با دیگر VCSها است. این امر موجب می‌شود تا Git تجدیدنظری نسبت به تمامی ابعاد کنترل نسخه داشته باشد، که اکثریت دیگر سیستم‌ها از نسل‌های قبل از خود به ارث برده‌اند. این موضوع باعث شده است تا Git از یک VCS ساده، به سیستم فایلی کوچکی بدل شود که در بالادست آن ابزار قدرتمند باورنکردنی بنا شده است. در فصل 3 بعضی از مزایای چنین دیدگاهی نسبت به داده، پوشش داده می‌شود. + +### تقریباً تمام عملیات به صورت محلی انجام می‌پذیرد ### + +اکثر عملیاتی که در Git انجام می‌پذیرد جهت اجرا تنها نیازمند فایل‌ها و منابع محلی هستند - به‌طور کلی نیازمند هیچ‌گونه اطلاعاتی از کامپیوتری دیگر در شبکه نیست. اگر شما فردی هستید که به CVCSای عادت کرده‌اید که در آن اکثر فعالیت‌ها دارای افزونگی رکود شبکه‌ای داشته‌اند، شاید این مزیت Git این فکر را برای شما تداعی کند که خدایان سرعت Git را با قدرتی وصف ناشدنی مورد لطف و رحمت قرار داده‌اند. از آن جهت که تمامی تاریخچه پروژه برروی دیسک محلی قرار دارد، به نظر می‌رسد که اکثر عملیات به صورت لحظه‌ای و بلادرنگ انجام می‌پذیرند. + +به عنوان مثال، Git برای نمایش تاریخچه پروژه نیازی جهت مراجعه به سرور برای اخذ تاریخچه و نمایش آن ندارد - Git این عمل را با خواندن مستقیم پایگاه داده محلی انجام می‌دهد. این بدان معناست که شخص می‌تواند تاریخچه پروژه را تقریباً بلادرنگ مشاهده کند. اگر نیاز به مشاهده تغییرات بین نسخه فعلی یک فایل با نسخه یک ماه قبل از آن باشد، Git می‌تواند به‌جای آن‌که از سرور درخواست این عمل را داشته باشد و یا آن‌که نسخه قبلی را از سرور خارجی فراخوانی و سپس مقایسه محلی را انجام دهد، این عمل را با نگاهی به نسخه یک ماه قبل فایل و انجام محاسبات محلی تغییرات رخ داده، انجام می‌دهد. + +همچنین بدین معناست که در صورت آفلاین بودن و یا وصل نبودن به VPN دامنه عملکرد شخص زیاد محدود نمی‌شود. اگر سوار بر هواپیما یا قطار شده باشید و تصمیم به انجام کاری داشته باشید، می‌توانید به راحتی commit را انجام داده و زمانی که دسترسی به شبکه پیدا کردید آپلود را انجام دهید. اگر به خانه رفته باشید و قادر به فعال سازی VPN خود نشده باشید، باز هم وقفه‌ای در کار شما حاصل نمی‌شود. در اکثریت دیگر سیستم‌ها انجام این موارد غیرممکن یا به سختی انجام می‌پذیرد. به عنوان مثال در Perforce، در صورتی که به شبکه متصل نباشید در واقع توانایی انجام کاری نخواهید داشت؛ در Subversion و CVS، امکان دست‌کاری فایل‌ها برای شما وجود دارد، ولی برای commit تغییرات روی پایگاه داده محدودیت دارید (زیرا اتصال شما به پایگاه داده بر قرار نیست). شاید این موضوع مسئله مهمی به نظر نیاید، ولی شاید با مشاهده تفاوت‌های بزرگی که می‌تواند به موجب آن ایجاد شود، شگفت زده شوید. + +### Git صداقت دارد ### + +هرچیزی که بخواهد در Git ذخیره شود، ابتدا checksum آن محاسبه می‌شود و سپس به‌وسیله همین checksum ارجاع داده می‌شود. چنین عملی موجب می‌شود که در صورت ایجاد کوچکترین تغییری در محتویات فایل یا پوشه‌ای، Git از آن آگاهی پیدا کند. این دستورالعمل در Git در پایینترین سطح پیاده‌سازی شده است و تأییدی بر صحت فلسفه Git دارد. بدین دلیل است که اگر داده‌ای در حین انتقال از دست برود و یا فایلی مخدوش شود، Git به سرعت از آن اطلاع پیدا می‌کند. + +مکانیزمی که Git برای تولید checksum استفاده می‌کند، هش SHA-1 است. این هش یک رشته 40 کاراکتری از کاراکترهای مبنای شانزده است (0 - 9 و a - f) که از روی محتویات فایل و یا ساختار پوشه موردنظر در Git محاسبه می‌گردد. در ادامه یک نمونه از هش SHA-1 آورده شده است: + + + 24b9da6552252987aa493b52f8696cd6d3b00373 + +به علت استفاده زیاد Git از این هش، به کرات در جای جای Git مشاهده‌گر این هش‌ها خواهید بود. در واقع، Git از نام فایل برای ذخیره‌سازی آن استفاده نمی‌کند بلکه Git از هش تولید شده از محتویات فایل مربوطه برای آدرس دهی آن در پایگاه داده خود بهره می‌گیرد. + +### عموماً Git فقط داده اضافه میکند ### + +هرگاه عملی در Git انجام می‌پذیرد، تقریباً در تمامی موارد Git داده‌ای به داده‌های خود در پایگاه داده اضافه می‌کند. انجام دادن عملی در این سیستم که برگشت‌پذیر نباشد یا باعث حذف داده ای از سیستم شود، بسیار سخت است. مشابه اکثر VCSها، فرد می‌تواند تا قبل از commit هرگونه تغییراتی را انجام دهد؛ ولی به محض commit یک تصویر لحظه‌ای در Git، امکان حذف آن بسیار سخت است، مخصوصاً اگر فرد عادتاً پایگاه داده خود را به مخزن دیگری push کند. + +این قابلیت باعث می‌شود که استفاده از Git، به عملی فرح بخش تبدیل شود زیرا فرد خواهد توانست بدون در خطر انداختن چیزی دست به هرگونه آزمایشی بزند. برای آشنایی بیشتر با چگونگی ذخیره‌سازی و بازیابی داده‌ها در Git که به نظر از دست رفته می‌باشند، می‌توانید به فصل 9 مراجعه کنید. + +### سه وضعیت ### + +توجه، توجه. اگر می‌خواهید پروسه یادگیری Git را بدون دردسر ادامه دهید، این بخش را به دقت مطالعه کنید. فایلها در Git می‌توانند در سه وضعیت اصلی قرار داشته باشند: committed، modified و staged. committed بدین معناست که فایل موردنظر در پایگاه داده محلی ذخیره شده است. modified یعنی تغییری در فایل ایجاد شده است ولی هنوز commitای از این فایل روی پایگاه داده انجام نگرفته است. فایلی که در وضعیت staged قرار گرفته است، فایلی تغییر یافته است که نسخه فعلی آن در تصویر لحظه‌ای بعدی جهت commit نشانه‌گذاری شده است. + +حال می‌توان سه بخش اصلی پروژه Git را معرفی کرد: پوشه Git، پوشه در حال کار (working directory) و staging area. + +Insert 18333fig0106.png +تصویر 1-6. پوشه در حال کار، staging area و پوشه Git + +در Git، metadata و پایگاه داده پروژه در پوشه Git ذخیره می‌شوند. این قسمت مهمترین بخش Git است، در واقع هنگامی که از مخزن کامپیوتری cloneای گرفته می‌شود، کپی از این پوشه ایجاد می‌گردد. + +پوشه در حال کار، checkout منفردی از نسخه‌ای از پروژه است. فایل‌های این بخش، فایل‌هایی می‌باشند که از پایگاه داده فشرده واقع در پوشه Git بیرون کشیده شده و جهت استفاده و ایجاد تغییر بر روی دیسک قرار داده شده‌اند. + +staging area عموماً از یک فایل ساده تشکیل شده است که محتوی اطلاعاتی است که مشخص می‌کند که چه چیزهایی در commit بعدی قرار می‌گیرند. معمولاً این فایل را index می‌نامند ولی عبارت staging area نیز در حال تبدیل شدن به نامی استاندارد برای چنین فایلی است. + +روند کاری Git عموماً به صورت ذیل است: + +1. ایجاد تغییرات روی فایل‌های واقع در پوشه در حال کار. +2. stage کردن فایل‌ها و اضافه کردن تصاویر لحظه‌ای فایلها به staging area. +3. commit کردن، که به موجب آن وضعیت فعلی فایل‌ها در staging area تحت یک تصویر لحظه‌ای به صورت دائمی در پوشه Git ذخیره می‌گردد. + +اگر نسخه‌ای از یک فایل در پوشه git قرار داشته باشد، commit شده فرض می‌شود. اگر تغییری در فایل ایجاد شده باشد و به staging area اضافه شده باشد، گوییم staged شده است. و اگر در فایل از آخرین مرتبه‌ای که checkout شده است تغییری ایجاد شده باشد ولی staged نشده باشد، گوییم modified شده است. در فصل 2، با این وضعیت‌ها بیشتر آشنا خواهید شد و یاد خواهید گرفت که چگونه می‌توان از آن‌ها به نحو احسنت استفاده کرد و یا حتی به صورت کامل از روی مرحله stage پرش کرد. + +## نصب Git ## + +حال وقت آن است که کار با Git را شروع کنیم. اول از هر چیز می‌بایست Git را نصب کرد. روشهای مختلفی برای این کار وجود دارد؛ دو مورد از رایج‌ترین این روش‌ها نصب از طریق سورس یا نصب به واسطه بسته‌های موجودی است که برای پلتفرم موردنظر شما تهیه شده است. + +### نصب از طریق سورس ### + +اگر امکان نصب از طریق سورس برای شما وجود دارد، این روش مناسب‌ترین روش جهت نصب می‌باشد، زیرا شما بعد از نصب آخرین نسخه نرم‌افزار را در اختیار خواهید داشت. در هر نسخه از Git سعی شده است که تا در رابط کاربری بهبودهایی حاصل شود، بنابراین در اختیار داشتن آخرین نسخه بهترین گزینه است البته اگر با کامپایل سورس نرم‌افزار مشکلی نداشته باشید. همچنین معمولاً مخازن نرم افزاری اکثر توزیعهای لینوکس دربردارنده بسته‌هایی با نسخه‌های قدیمی هستند؛ بنابراین در صورتی که شما توسعه دهنده‌ای به روز هستید یا از backportها استفاده می‌کنید، نصب از طریق سورس بهترین انتخاب برای شما است. + +برای نصب Git نیاز به کتابخانه های curl، zlib، openssl، expat و libiconv است که Git نیازمند آنهاست. به عنوان مثال، اگر روی سیستمی کار می‌کنید که yum (مانند Fedora) یا apt-get (مانند سیستم های مبتنی بر Debian) دارد، می‌توانید برای نصب این بسته‌های نیازمندی از دستورهای ذیل استفاده کنید: + + $ yum install curl-devel expat-devel gettext-devel \ + openssl-devel zlib-devel + + $ apt-get install libcurl4-gnutls-dev libexpat1-dev gettext \ + libz-dev libssl-dev + +حال که تمامی نیازمندی‌ها نصب گردید، می‌توان آخرین نسخه Git را از وب سایت آن دانلود کرد: + + http://git-scm.com/download + +و آن را کامپایل و نصب نمود: + + $ tar -zxf git-1.7.2.2.tar.gz + $ cd git-1.7.2.2 + $ make prefix=/usr/local all + $ sudo make prefix=/usr/local install + +بعد از کامل شدن این مراحل می‌توان از خود Git برای دریافت آپدیت‌های Git استفاده کرد: + + $ git clone git://git.kernel.org/pub/scm/git/git.git + +### نصب بر روی لینوکس ### + +اگر قصد نصب Git بر روی لینوکس به واسطه یک نصاب باینری را دارید، می‌توانید این کار را از طریق ابزار مدیریت بسته های نرم‌افزاری که همراه توزیع موردنظر شما ارائه می‌شود انجام دهید. اگر توزیع شما Fedora است، می‌توانید از yum استفاده کنید: + + $ yum install git-core + +یا اگر توزیعی مبتنی بر Debian مانند Ubuntu دارید، می‌توانید از apt-get استفاده کنید: + + $ apt-get install git + +### نصب برروی Mac ### + +برای نصب برروی Mac دو روش آسان وجود دارد. آسان‌ترین روش استفاده از نصاب گرافیکی Git است، که امکان دانلود آن از صفحه Google Code وجود دارد (تصویر 1-7): + + http://code.google.com/p/git-osx-installer + +Insert 18333fig0107.png +تصویر 1-7. نصاب Git OS X + +روش دیگر نصب از طریق MacPortها (`http://www.macports.org`) است. اگر MacPortها را نصب شده روی سیستم خود دارید، می‌توانید Git را با دستور ذیل نصب کنید + + $ sudo port install git-core +svn +doc +bash_completion +gitweb + +نیازی به افزودن تمامی اضافات نیست، ولی شاید برای استفاده از Git به همراه مخازن Subversion، احتمالاً افزودن +svn گزینه مناسبی است. + +### نصب بر روی ویندوز ### + +نصب Git روی ویندوز بسیار آسان است. پروژه msysGit یکی از آسان‌ترین مراحل نصب را دارد. تنها نیاز است که فایل نصاب exe را از صفحه GitHub دانلود، و آن را اجرا کرد: + + http://msysgit.github.com/ + +بعد از اتمام نصب، هم نسخه خط فرمان (شامل SSH client که در ادامه مشاهده خواهد شد که ابزاری کارآمد است) و هم رابط گرافیکی استاندارد را در اختیار خواهید داشت. + +نکته برای کابران ویندوز: کاربر باید جهت کار با Git از پوسته ارائه شده به همراه msysGit (به سبک Unix) استفاده کند، تا بتواند دستورات چند خطی پیچیده‌ای که در این کتاب آورده شده را اجرا کند. اگر به هر دلیلی، نیاز به استفاده از پوسته خود ویندوز/کنسول خط فرمان، شدید باید در عوض تک کوت (simple quote) از دابل کوت (برای پارامترهایی که در بر دارنده فاصله هستند) استفاده کنید و باید پارامترهای موجود در آخرین خط که با circumflex accent (^) به پایان می‌رسند را داخل کوت قرار دهید، زیرا این علامت، نشانگر ادامه دار بودن خط در ویندوز است. + +## تنظیمات شروع به کار Git ## + +حال که Git روی سیستم نصب شده است، نیاز به شخصی‌سازی بعضی از منابع Git است. انجام این تنظیمات فقط برای یک مرتبه انجام می‌پذیرد؛ و بعد از آن با هر بار ارتقاء بدون تغییر باقی می‌مانند. همچنین امکان تغییر آن‌ها در هر زمانی که نیاز باشد به کمک خط فرمان وجود دارد. + +به همراه Git ابزاری ارائه شده است با نام git config که امکان خواندن و اعمال متغیرهای تنظیماتی که تمامی ابعاد ظاهری و عملیاتی Git را کنترل می‌کند فراهم می‌سازد. + +* فایل `/etc/gitconfig`: حاوی مقادیر تمامی کاربران سیستم و مخازن آن‌ها است. اگر به همراه `git config` از گزینه `--system` استفاده شود، خواندن و نوشتن به صورت اختصاصی از این فایل انجام می‌پذیرد. +* فایل `~/.gitconfig`: مختص کاربر مشخصی است. با استفاده از گزینه `--global` خواندن و نوشتن Git به صورت اختصاصی از این فایل انجام می‌پذیرد. +* فایل config موجود در پوشه git (`.git/config`) یا هر مخزنی که در حال استفاده از آن می‌باشید: مختص یک مخزن خاص است. مقادیر هر سطح باعث لغو مقادیر سطح قبلی خود می‌شود. بنابراین مقادیر `.git/config` موجب لغو مقادیر `/etc/gitconfig` خواهد شد. + +در سیستم‌های ویندوزی، Git در پوشه `$HOME` (متغیر محیطی `%USERPROFILE%` در ویندوز) که برای اکثر کاربران با توجه به نسخه سیستم در مسیرهای `C:\Documents and Settings\$USER‍ یا `C:\Users\$USER` (`$USER‍ در ویندوز متغیر محیطی `%USERNAME%`) قرار دارد، فایل `.gitconfig` را جستجو می‌کند. همچنین نسبت به مسیر ریشه MSys که همان مسیر نصب انتخاب شده در هنگام اجرای نصاب Git در ویندوز می‌باشد، به دنبال فایلی با نام /etc/gitconfig می‌گردد. + +### شناسه کاربر ### + +اولین عملی که بعد از نصب Git باید انجام شود، مقداردهی دو متغیر نام کاربری (user name) و آدرس پست الکترونیکی (e-mail address) است. این عمل از آن جهت اهمیت دارد که در هر commit این اطلاعات به‌صورتی تغییر ناپذیر روی commit انجام شده حک می‌شوند. + + $ git config --global user.name "John Doe" + $ git config --global user.email johndoe@example.com + +مجدداً یادآوری می‌شود که انجام این عمل در صورت استفاده از گزینه `--global` فقط یک مرتبه انجام می‌پذیرد، زیرا Git برای هر عملی که در سیستم انجام می‌پذیرد از این اطلاعات استفاده می‌کند. حال اگر فرد نیاز به استفاده از نام و آدرس پست الکترونیکی متفاوتی برای پروژه‌های خاصی دارد، می‌تواند با اجرای همان دستورات البته بدون استفاده از گزینه `--global` هنگامی که در مسیر پروژه مذکور قرار دارد به مقصود خود دست یابد. + +### ویرایشگر کاربر ### + +حال که شناسه تنظیم شد، می‌توان ویرایشگر متن پیش فرضی را معرفی کرد تا هنگامی که نیاز به درج پیغامی در Git است فراخوانی شود. به صورت پیش فرض Git از ویرایشگر پیش فرض سیستم برای این امر استفاده می کند، که معمولاً Vi یا Vim است. اگر نظر شخص به استفاده از ویرایشگر متنی متفاوتی مانند Emacs باشد، می‌توان به صورت ذیل عمل کرد: + + $ git config --global core.editor emacs + +### ابزار Diff ### + +ابزار مفید دیگری که شاید نیاز به تنظیم داشته باشد، ابزار diff پیش فرضی است که برای رفع مغایرت ایجاد شده در هنگام اجرای دستور merge استفاده می‌گردد. به عنوان مثال اگر هدف استفاده از vimdiff باشد خواهیم داشت: + + $ git config --global merge.tool vimdiff + +سGit از ابزارهای kdiff3، tkdiff، meld، xxdiff، emerge، vimdiff، gvimdiff، ecmerge و opendiff جهت merge پشتیبانی می‌کند. با این وجود امکان تعریف ابزاری شخصی نیز وجود دارد؛ برای اطلاعات بیشتر جهت انجام این مورد می‌توانید به فصل 7 مراجعه کنید. + +### بررسی تنظیمات ### + +برای مشاهده و بررسی تنظیمات، می‌توان از دستور `git config --list` استفاده کرد که در نتیجه آن Git تمامی تنظیمات موجود تا آن لحظه را در قالب لیستی نمایش می‌دهد: + + $ git config --list + user.name=Scott Chacon + user.email=schacon@gmail.com + color.status=auto + color.branch=auto + color.interactive=auto + color.diff=auto + ... + +احتمال دارد در این لیست کلیدهایی بیش از یک بار مشاهده شوند، دلیل این امر آن است که Git کلید مشابهی را از فایل‌های مختلفی (مانند `/etc/giconfig` و `~/.gitconfig`) خوانده است. در این‌گونه موارد، Git آخرین مقدار کلید منحصر به فردی که مشاهده می‌کند را جهت استفاده به‌کار می‌گیرد. + +همچنین برای مشاهده مقدار مورد استفاده یک کلید خاص توسط Git، می‌توان از دستور `git config {key}` استفاده کرد: + + $ git config user.name + Scott Chacon + +## دریافت راهنمایی ## + +هرگاه در استفاده از Git نیازمند راهنمایی بودید، سه روش برای مشاهده صفحه راهنما هرگونه دستوری در Git وجود دارد: + + $ git help + $ git --help + $ man git- + +برای مثال، برای مشاهده صفحه راهنما دستور config داریم + + $ git help config + +این دستورات از آن جهت که می‌توان از هر مکانی، حتی در حالت آفلاین، به آن‌ها دسترسی پیدا کرد ابزاری کاربردی می‌باشند. +اگر صفحات راهنما و این کتاب جوابگوی نیاز شما نبودند و نیاز به راهنمایی فردی پیدا کردید، میتوانید به کانالهای `#git` یا `#github` در سرور Freenode IRC (irc.freenode.net) مراجعه کنید. +معمولاً این کانال‌ها مملؤ از افرادی با سطح دانش بالا در زمینه Git هستند که آماده راهنمایی رساندن به شما می‌باشند. + +## خلاصه ## + +با مطالعه این فصل شما باید درک اولیه‌ای از این که Git چیست و چه تفاوتی با دیگر CVCSهایی که احتمالاً از آن استفاده می‌کردید دارد پیدا کرده باشد. همچنین شما باید نسخه آماده به کاری از Git را روی سیستم خود داشته باشید که شناسه شخصی شما برروی آن تنظیم شده است. حال زمان یادگیری اصول اولیه Git است. diff --git a/fa/03-git-branching/01-chapter3.markdown b/fa/03-git-branching/01-chapter3.markdown new file mode 100644 index 000000000..f5e2663bd --- /dev/null +++ b/fa/03-git-branching/01-chapter3.markdown @@ -0,0 +1,608 @@ +# Git Branching # + +تقریبا تمام انواع VCS نوعی از انشعاب را پشتیبانی میکنند. + +Nearly every VCS has some form of branching support. Branching means you diverge from the main line of development and continue to do work without messing with that main line. In many VCS tools, this is a somewhat expensive process, often requiring you to create a new copy of your source code directory, which can take a long time for large projects. + +Some people refer to the branching model in Git as its “killer feature” , and it certainly sets Git apart in the VCS community. Why is it so special? The way Git branches is incredibly lightweight, making branching operations nearly instantaneous and switching back and forth between branches generally just as fast. Unlike many other VCSs, Git encourages a workflow that branches and merges often, even multiple times in a day. Understanding and mastering this feature gives you a powerful and unique tool and can literally change the way that you develop. + +## What a Branch Is ## + +To really understand the way Git does branching, we need to take a step back and examine how Git stores its data. As you may remember from Chapter 1, Git doesn’t store data as a series of changesets or deltas, but instead as a series of snapshots. + +When you commit in Git, Git stores a commit object that contains a pointer to the snapshot of the content you staged, the author and message metadata, and zero or more pointers to the commit or commits that were the direct parents of this commit: zero parents for the first commit, one parent for a normal commit, and multiple parents for a commit that results from a merge of two or more branches. + +To visualize this, let’s assume that you have a directory containing three files, and you stage them all and commit. Staging the files checksums each one (the SHA-1 hash we mentioned in Chapter 1), stores that version of the file in the Git repository (Git refers to them as blobs), and adds that checksum to the staging area: + + $ git add README test.rb LICENSE + $ git commit -m 'initial commit of my project' + +Running `git commit` checksums all project directories and stores them as `tree` objects in the Git repository. Git then creates a `commit` object that has the metadata and a pointer to the root project `tree` object so it can re-create that snapshot when needed. + +Your Git repository now contains five objects: one blob for the contents of each of your three files, one tree that lists the contents of the directory and specifies which file names are stored as which blobs, and one commit with the pointer to that root tree and all the commit metadata. Conceptually, the data in your Git repository looks something like Figure 3-1. + +Insert 18333fig0301.png +Figure 3-1. Single commit repository data. + +If you make some changes and commit again, the next commit stores a pointer to the commit that came immediately before it. After two more commits, your history might look something like Figure 3-2. + +Insert 18333fig0302.png +Figure 3-2. Git object data for multiple commits. + +A branch in Git is simply a lightweight movable pointer to one of these commits. The default branch name in Git is master. As you initially make commits, you’re given a `master` branch that points to the last commit you made. Every time you commit, it moves forward automatically. + +Insert 18333fig0303.png +Figure 3-3. Branch pointing into the commit data’s history. + +What happens if you create a new branch? Well, doing so creates a new pointer for you to move around. Let’s say you create a new branch called testing. You do this with the `git branch` command: + + $ git branch testing + +This creates a new pointer at the same commit you’re currently on (see Figure 3-4). + +Insert 18333fig0304.png +Figure 3-4. Multiple branches pointing into the commit’s data history. + +How does Git know what branch you’re currently on? It keeps a special pointer called HEAD. Note that this is a lot different than the concept of HEAD in other VCSs you may be used to, such as Subversion or CVS. In Git, this is a pointer to the local branch you’re currently on. In this case, you’re still on master. The `git branch` command only created a new branch — it didn’t switch to that branch (see Figure 3-5). + +Insert 18333fig0305.png +Figure 3-5. HEAD file pointing to the branch you’re on. + +To switch to an existing branch, you run the `git checkout` command. Let’s switch to the new testing branch: + + $ git checkout testing + +This moves HEAD to point to the testing branch (see Figure 3-6). + +Insert 18333fig0306.png +Figure 3-6. HEAD points to another branch when you switch branches. + +What is the significance of that? Well, let’s do another commit: + + $ vim test.rb + $ git commit -a -m 'made a change' + +Figure 3-7 illustrates the result. + +Insert 18333fig0307.png +Figure 3-7. The branch that HEAD points to moves forward with each commit. + +This is interesting, because now your testing branch has moved forward, but your `master` branch still points to the commit you were on when you ran `git checkout` to switch branches. Let’s switch back to the `master` branch: + + $ git checkout master + +Figure 3-8 shows the result. + +Insert 18333fig0308.png +Figure 3-8. HEAD moves to another branch on a checkout. + +That command did two things. It moved the HEAD pointer back to point to the `master` branch, and it reverted the files in your working directory back to the snapshot that `master` points to. This also means the changes you make from this point forward will diverge from an older version of the project. It essentially rewinds the work you’ve done in your testing branch temporarily so you can go in a different direction. + +Let’s make a few changes and commit again: + + $ vim test.rb + $ git commit -a -m 'made other changes' + +Now your project history has diverged (see Figure 3-9). You created and switched to a branch, did some work on it, and then switched back to your main branch and did other work. Both of those changes are isolated in separate branches: you can switch back and forth between the branches and merge them together when you’re ready. And you did all that with simple `branch` and `checkout` commands. + +Insert 18333fig0309.png +Figure 3-9. The branch histories have diverged. + +Because a branch in Git is in actuality a simple file that contains the 40 character SHA-1 checksum of the commit it points to, branches are cheap to create and destroy. Creating a new branch is as quick and simple as writing 41 bytes to a file (40 characters and a newline). + +This is in sharp contrast to the way most VCS tools branch, which involves copying all of the project’s files into a second directory. This can take several seconds or even minutes, depending on the size of the project, whereas in Git the process is always instantaneous. Also, because we’re recording the parents when we commit, finding a proper merge base for merging is automatically done for us and is generally very easy to do. These features help encourage developers to create and use branches often. + +Let’s see why you should do so. + +## Basic Branching and Merging ## + +Let’s go through a simple example of branching and merging with a workflow that you might use in the real world. You’ll follow these steps: + +1. Do work on a web site. +2. Create a branch for a new story you’re working on. +3. Do some work in that branch. + +At this stage, you’ll receive a call that another issue is critical and you need a hotfix. You’ll do the following: + +1. Switch back to your production branch. +2. Create a branch to add the hotfix. +3. After it’s tested, merge the hotfix branch, and push to production. +4. Switch back to your original story and continue working. + +### Basic Branching ### + +First, let’s say you’re working on your project and have a couple of commits already (see Figure 3-10). + +Insert 18333fig0310.png +Figure 3-10. A short and simple commit history. + +You’ve decided that you’re going to work on issue #53 in whatever issue-tracking system your company uses. To be clear, Git isn’t tied into any particular issue-tracking system; but because issue #53 is a focused topic that you want to work on, you’ll create a new branch in which to work. To create a branch and switch to it at the same time, you can run the `git checkout` command with the `-b` switch: + + $ git checkout -b iss53 + Switched to a new branch 'iss53' + +This is shorthand for: + + $ git branch iss53 + $ git checkout iss53 + +Figure 3-11 illustrates the result. + +Insert 18333fig0311.png +Figure 3-11. Creating a new branch pointer. + +You work on your web site and do some commits. Doing so moves the `iss53` branch forward, because you have it checked out (that is, your HEAD is pointing to it; see Figure 3-12): + + $ vim index.html + $ git commit -a -m 'added a new footer [issue 53]' + +Insert 18333fig0312.png +Figure 3-12. The iss53 branch has moved forward with your work. + +Now you get the call that there is an issue with the web site, and you need to fix it immediately. With Git, you don’t have to deploy your fix along with the `iss53` changes you’ve made, and you don’t have to put a lot of effort into reverting those changes before you can work on applying your fix to what is in production. All you have to do is switch back to your master branch. + +However, before you do that, note that if your working directory or staging area has uncommitted changes that conflict with the branch you’re checking out, Git won’t let you switch branches. It’s best to have a clean working state when you switch branches. There are ways to get around this (namely, stashing and commit amending) that we’ll cover later. For now, you’ve committed all your changes, so you can switch back to your master branch: + + $ git checkout master + Switched to branch 'master' + +At this point, your project working directory is exactly the way it was before you started working on issue #53, and you can concentrate on your hotfix. This is an important point to remember: Git resets your working directory to look like the snapshot of the commit that the branch you check out points to. It adds, removes, and modifies files automatically to make sure your working copy is what the branch looked like on your last commit to it. + +Next, you have a hotfix to make. Let’s create a hotfix branch on which to work until it’s completed (see Figure 3-13): + + $ git checkout -b hotfix + Switched to a new branch 'hotfix' + $ vim index.html + $ git commit -a -m 'fixed the broken email address' + [hotfix 3a0874c] fixed the broken email address + 1 files changed, 1 deletion(-) + +Insert 18333fig0313.png +Figure 3-13. hotfix branch based back at your master branch point. + +You can run your tests, make sure the hotfix is what you want, and merge it back into your master branch to deploy to production. You do this with the `git merge` command: + + $ git checkout master + $ git merge hotfix + Updating f42c576..3a0874c + Fast-forward + README | 1 - + 1 file changed, 1 deletion(-) + +You’ll notice the phrase "Fast-forward" in that merge. Because the commit pointed to by the branch you merged in was directly upstream of the commit you’re on, Git moves the pointer forward. To phrase that another way, when you try to merge one commit with a commit that can be reached by following the first commit’s history, Git simplifies things by moving the pointer forward because there is no divergent work to merge together — this is called a "fast forward". + +Your change is now in the snapshot of the commit pointed to by the `master` branch, and you can deploy your change (see Figure 3-14). + +Insert 18333fig0314.png +Figure 3-14. Your master branch points to the same place as your hotfix branch after the merge. + +After your super-important fix is deployed, you’re ready to switch back to the work you were doing before you were interrupted. However, first you’ll delete the `hotfix` branch, because you no longer need it — the `master` branch points at the same place. You can delete it with the `-d` option to `git branch`: + + $ git branch -d hotfix + Deleted branch hotfix (was 3a0874c). + +Now you can switch back to your work-in-progress branch on issue #53 and continue working on it (see Figure 3-15): + + $ git checkout iss53 + Switched to branch 'iss53' + $ vim index.html + $ git commit -a -m 'finished the new footer [issue 53]' + [iss53 ad82d7a] finished the new footer [issue 53] + 1 file changed, 1 insertion(+) + +Insert 18333fig0315.png +Figure 3-15. Your iss53 branch can move forward independently. + +It’s worth noting here that the work you did in your `hotfix` branch is not contained in the files in your `iss53` branch. If you need to pull it in, you can merge your `master` branch into your `iss53` branch by running `git merge master`, or you can wait to integrate those changes until you decide to pull the `iss53` branch back into `master` later. + +### Basic Merging ### + +Suppose you’ve decided that your issue #53 work is complete and ready to be merged into your `master` branch. In order to do that, you’ll merge in your `iss53` branch, much like you merged in your `hotfix` branch earlier. All you have to do is check out the branch you wish to merge into and then run the `git merge` command: + + $ git checkout master + $ git merge iss53 + Auto-merging README + Merge made by the 'recursive' strategy. + README | 1 + + 1 file changed, 1 insertion(+) + +This looks a bit different than the `hotfix` merge you did earlier. In this case, your development history has diverged from some older point. Because the commit on the branch you’re on isn’t a direct ancestor of the branch you’re merging in, Git has to do some work. In this case, Git does a simple three-way merge, using the two snapshots pointed to by the branch tips and the common ancestor of the two. Figure 3-16 highlights the three snapshots that Git uses to do its merge in this case. + +Insert 18333fig0316.png +Figure 3-16. Git automatically identifies the best common-ancestor merge base for branch merging. + +Instead of just moving the branch pointer forward, Git creates a new snapshot that results from this three-way merge and automatically creates a new commit that points to it (see Figure 3-17). This is referred to as a merge commit and is special in that it has more than one parent. + +It’s worth pointing out that Git determines the best common ancestor to use for its merge base; this is different than CVS or Subversion (before version 1.5), where the developer doing the merge has to figure out the best merge base for themselves. This makes merging a heck of a lot easier in Git than in these other systems. + +Insert 18333fig0317.png +Figure 3-17. Git automatically creates a new commit object that contains the merged work. + +Now that your work is merged in, you have no further need for the `iss53` branch. You can delete it and then manually close the ticket in your ticket-tracking system: + + $ git branch -d iss53 + +### Basic Merge Conflicts ### + +Occasionally, this process doesn’t go smoothly. If you changed the same part of the same file differently in the two branches you’re merging together, Git won’t be able to merge them cleanly. If your fix for issue #53 modified the same part of a file as the `hotfix`, you’ll get a merge conflict that looks something like this: + + $ git merge iss53 + Auto-merging index.html + CONFLICT (content): Merge conflict in index.html + Automatic merge failed; fix conflicts and then commit the result. + +Git hasn’t automatically created a new merge commit. It has paused the process while you resolve the conflict. If you want to see which files are unmerged at any point after a merge conflict, you can run `git status`: + + $ git status + On branch master + You have unmerged paths. + (fix conflicts and run "git commit") + + Unmerged paths: + (use "git add ..." to mark resolution) + + both modified: index.html + + no changes added to commit (use "git add" and/or "git commit -a") + +Anything that has merge conflicts and hasn’t been resolved is listed as unmerged. Git adds standard conflict-resolution markers to the files that have conflicts, so you can open them manually and resolve those conflicts. Your file contains a section that looks something like this: + + <<<<<<< HEAD + + ======= + + >>>>>>> iss53 + +This means the version in HEAD (your master branch, because that was what you had checked out when you ran your merge command) is the top part of that block (everything above the `=======`), while the version in your `iss53` branch looks like everything in the bottom part. In order to resolve the conflict, you have to either choose one side or the other or merge the contents yourself. For instance, you might resolve this conflict by replacing the entire block with this: + + + +This resolution has a little of each section, and I’ve fully removed the `<<<<<<<`, `=======`, and `>>>>>>>` lines. After you’ve resolved each of these sections in each conflicted file, run `git add` on each file to mark it as resolved. Staging the file marks it as resolved in Git. +If you want to use a graphical tool to resolve these issues, you can run `git mergetool`, which fires up an appropriate visual merge tool and walks you through the conflicts: + + $ git mergetool + + This message is displayed because 'merge.tool' is not configured. + See 'git mergetool --tool-help' or 'git help config' for more details. + 'git mergetool' will now attempt to use one of the following tools: + opendiff kdiff3 tkdiff xxdiff meld tortoisemerge gvimdiff diffuse diffmerge ecmerge p4merge araxis bc3 codecompare vimdiff emerge + Merging: + index.html + + Normal merge conflict for 'index.html': + {local}: modified file + {remote}: modified file + Hit return to start merge resolution tool (opendiff): + +If you want to use a merge tool other than the default (Git chose `opendiff` for me in this case because I ran the command on a Mac), you can see all the supported tools listed at the top after “... one of the following tools:”. Type the name of the tool you’d rather use. In Chapter 7, we’ll discuss how you can change this default value for your environment. + +After you exit the merge tool, Git asks you if the merge was successful. If you tell the script that it was, it stages the file to mark it as resolved for you. + +You can run `git status` again to verify that all conflicts have been resolved: + + $ git status + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: index.html + + +If you’re happy with that, and you verify that everything that had conflicts has been staged, you can type `git commit` to finalize the merge commit. The commit message by default looks something like this: + + Merge branch 'iss53' + + Conflicts: + index.html + # + # It looks like you may be committing a merge. + # If this is not correct, please remove the file + # .git/MERGE_HEAD + # and try again. + # + +You can modify that message with details about how you resolved the merge if you think it would be helpful to others looking at this merge in the future — why you did what you did, if it’s not obvious. + +## Branch Management ## + +Now that you’ve created, merged, and deleted some branches, let’s look at some branch-management tools that will come in handy when you begin using branches all the time. + +The `git branch` command does more than just create and delete branches. If you run it with no arguments, you get a simple listing of your current branches: + + $ git branch + iss53 + * master + testing + +Notice the `*` character that prefixes the `master` branch: it indicates the branch that you currently have checked out. This means that if you commit at this point, the `master` branch will be moved forward with your new work. To see the last commit on each branch, you can run `git branch -v`: + + $ git branch -v + iss53 93b412c fix javascript issue + * master 7a98805 Merge branch 'iss53' + testing 782fd34 add scott to the author list in the readmes + +Another useful option to figure out what state your branches are in is to filter this list to branches that you have or have not yet merged into the branch you’re currently on. There are useful `--merged` and `--no-merged` options available in Git for this purpose. To see which branches are already merged into the branch you’re on, you can run `git branch --merged`: + + $ git branch --merged + iss53 + * master + +Because you already merged in `iss53` earlier, you see it in your list. Branches on this list without the `*` in front of them are generally fine to delete with `git branch -d`; you’ve already incorporated their work into another branch, so you’re not going to lose anything. + +To see all the branches that contain work you haven’t yet merged in, you can run `git branch --no-merged`: + + $ git branch --no-merged + testing + +This shows your other branch. Because it contains work that isn’t merged in yet, trying to delete it with `git branch -d` will fail: + + $ git branch -d testing + error: The branch 'testing' is not fully merged. + If you are sure you want to delete it, run 'git branch -D testing'. + +If you really do want to delete the branch and lose that work, you can force it with `-D`, as the helpful message points out. + +## Branching Workflows ## + +Now that you have the basics of branching and merging down, what can or should you do with them? In this section, we’ll cover some common workflows that this lightweight branching makes possible, so you can decide if you would like to incorporate it into your own development cycle. + +### Long-Running Branches ### + +Because Git uses a simple three-way merge, merging from one branch into another multiple times over a long period is generally easy to do. This means you can have several branches that are always open and that you use for different stages of your development cycle; you can merge regularly from some of them into others. + +Many Git developers have a workflow that embraces this approach, such as having only code that is entirely stable in their `master` branch — possibly only code that has been or will be released. They have another parallel branch named develop or next that they work from or use to test stability — it isn’t necessarily always stable, but whenever it gets to a stable state, it can be merged into `master`. It’s used to pull in topic branches (short-lived branches, like your earlier `iss53` branch) when they’re ready, to make sure they pass all the tests and don’t introduce bugs. + +In reality, we’re talking about pointers moving up the line of commits you’re making. The stable branches are farther down the line in your commit history, and the bleeding-edge branches are farther up the history (see Figure 3-18). + +Insert 18333fig0318.png +Figure 3-18. More stable branches are generally farther down the commit history. + +It’s generally easier to think about them as work silos, where sets of commits graduate to a more stable silo when they’re fully tested (see Figure 3-19). + +Insert 18333fig0319.png +Figure 3-19. It may be helpful to think of your branches as silos. + +You can keep doing this for several levels of stability. Some larger projects also have a `proposed` or `pu` (proposed updates) branch that has integrated branches that may not be ready to go into the `next` or `master` branch. The idea is that your branches are at various levels of stability; when they reach a more stable level, they’re merged into the branch above them. +Again, having multiple long-running branches isn’t necessary, but it’s often helpful, especially when you’re dealing with very large or complex projects. + +### Topic Branches ### + +Topic branches, however, are useful in projects of any size. A topic branch is a short-lived branch that you create and use for a single particular feature or related work. This is something you’ve likely never done with a VCS before because it’s generally too expensive to create and merge branches. But in Git it’s common to create, work on, merge, and delete branches several times a day. + +You saw this in the last section with the `iss53` and `hotfix` branches you created. You did a few commits on them and deleted them directly after merging them into your main branch. This technique allows you to context-switch quickly and completely — because your work is separated into silos where all the changes in that branch have to do with that topic, it’s easier to see what has happened during code review and such. You can keep the changes there for minutes, days, or months, and merge them in when they’re ready, regardless of the order in which they were created or worked on. + +Consider an example of doing some work (on `master`), branching off for an issue (`iss91`), working on it for a bit, branching off the second branch to try another way of handling the same thing (`iss91v2`), going back to your master branch and working there for a while, and then branching off there to do some work that you’re not sure is a good idea (`dumbidea` branch). Your commit history will look something like Figure 3-20. + +Insert 18333fig0320.png +Figure 3-20. Your commit history with multiple topic branches. + +Now, let’s say you decide you like the second solution to your issue best (`iss91v2`); and you showed the `dumbidea` branch to your coworkers, and it turns out to be genius. You can throw away the original `iss91` branch (losing commits C5 and C6) and merge in the other two. Your history then looks like Figure 3-21. + +Insert 18333fig0321.png +Figure 3-21. Your history after merging in dumbidea and iss91v2. + +It’s important to remember when you’re doing all this that these branches are completely local. When you’re branching and merging, everything is being done only in your Git repository — no server communication is happening. + +## Remote Branches ## + +Remote branches are references to the state of branches on your remote repositories. They’re local branches that you can’t move; they’re moved automatically whenever you do any network communication. Remote branches act as bookmarks to remind you where the branches on your remote repositories were the last time you connected to them. + +They take the form `(remote)/(branch)`. For instance, if you wanted to see what the `master` branch on your `origin` remote looked like as of the last time you communicated with it, you would check the `origin/master` branch. If you were working on an issue with a partner and they pushed up an `iss53` branch, you might have your own local `iss53` branch; but the branch on the server would point to the commit at `origin/iss53`. + +This may be a bit confusing, so let’s look at an example. Let’s say you have a Git server on your network at `git.ourcompany.com`. If you clone from this, Git automatically names it `origin` for you, pulls down all its data, creates a pointer to where its `master` branch is, and names it `origin/master` locally; and you can’t move it. Git also gives you your own `master` branch starting at the same place as origin’s `master` branch, so you have something to work from (see Figure 3-22). + +Insert 18333fig0322.png +Figure 3-22. A Git clone gives you your own master branch and origin/master pointing to origin’s master branch. + +If you do some work on your local master branch, and, in the meantime, someone else pushes to `git.ourcompany.com` and updates its master branch, then your histories move forward differently. Also, as long as you stay out of contact with your origin server, your `origin/master` pointer doesn’t move (see Figure 3-23). + +Insert 18333fig0323.png +Figure 3-23. Working locally and having someone push to your remote server makes each history move forward differently. + +To synchronize your work, you run a `git fetch origin` command. This command looks up which server origin is (in this case, it’s `git.ourcompany.com`), fetches any data from it that you don’t yet have, and updates your local database, moving your `origin/master` pointer to its new, more up-to-date position (see Figure 3-24). + +Insert 18333fig0324.png +Figure 3-24. The `git fetch` command updates your remote references. + +To demonstrate having multiple remote servers and what remote branches for those remote projects look like, let’s assume you have another internal Git server that is used only for development by one of your sprint teams. This server is at `git.team1.ourcompany.com`. You can add it as a new remote reference to the project you’re currently working on by running the `git remote add` command as we covered in Chapter 2. Name this remote `teamone`, which will be your shortname for that whole URL (see Figure 3-25). + +Insert 18333fig0325.png +Figure 3-25. Adding another server as a remote. + +Now, you can run `git fetch teamone` to fetch everything the remote `teamone` server has that you don’t have yet. Because that server has a subset of the data your `origin` server has right now, Git fetches no data but sets a remote branch called `teamone/master` to point to the commit that `teamone` has as its `master` branch (see Figure 3-26). + +Insert 18333fig0326.png +Figure 3-26. You get a reference to teamone’s master branch position locally. + +### Pushing ### + +When you want to share a branch with the world, you need to push it up to a remote that you have write access to. Your local branches aren’t automatically synchronized to the remotes you write to — you have to explicitly push the branches you want to share. That way, you can use private branches for work you don’t want to share, and push up only the topic branches you want to collaborate on. + +If you have a branch named `serverfix` that you want to work on with others, you can push it up the same way you pushed your first branch. Run `git push (remote) (branch)`: + + $ git push origin serverfix + Counting objects: 20, done. + Compressing objects: 100% (14/14), done. + Writing objects: 100% (15/15), 1.74 KiB, done. + Total 15 (delta 5), reused 0 (delta 0) + To git@github.com:schacon/simplegit.git + * [new branch] serverfix -> serverfix + +This is a bit of a shortcut. Git automatically expands the `serverfix` branchname out to `refs/heads/serverfix:refs/heads/serverfix`, which means, “Take my serverfix local branch and push it to update the remote’s serverfix branch.” We’ll go over the `refs/heads/` part in detail in Chapter 9, but you can generally leave it off. You can also do `git push origin serverfix:serverfix`, which does the same thing — it says, “Take my serverfix and make it the remote’s serverfix.” You can use this format to push a local branch into a remote branch that is named differently. If you didn’t want it to be called `serverfix` on the remote, you could instead run `git push origin serverfix:awesomebranch` to push your local `serverfix` branch to the `awesomebranch` branch on the remote project. + +The next time one of your collaborators fetches from the server, they will get a reference to where the server’s version of `serverfix` is under the remote branch `origin/serverfix`: + + $ git fetch origin + remote: Counting objects: 20, done. + remote: Compressing objects: 100% (14/14), done. + remote: Total 15 (delta 5), reused 0 (delta 0) + Unpacking objects: 100% (15/15), done. + From git@github.com:schacon/simplegit + * [new branch] serverfix -> origin/serverfix + +It’s important to note that when you do a fetch that brings down new remote branches, you don’t automatically have local, editable copies of them. In other words, in this case, you don’t have a new `serverfix` branch — you only have an `origin/serverfix` pointer that you can’t modify. + +To merge this work into your current working branch, you can run `git merge origin/serverfix`. If you want your own `serverfix` branch that you can work on, you can base it off your remote branch: + + $ git checkout -b serverfix origin/serverfix + Branch serverfix set up to track remote branch serverfix from origin. + Switched to a new branch 'serverfix' + +This gives you a local branch that you can work on that starts where `origin/serverfix` is. + +### Tracking Branches ### + +Checking out a local branch from a remote branch automatically creates what is called a _tracking branch_. Tracking branches are local branches that have a direct relationship to a remote branch. If you’re on a tracking branch and type `git push`, Git automatically knows which server and branch to push to. Also, running `git pull` while on one of these branches fetches all the remote references and then automatically merges in the corresponding remote branch. + +When you clone a repository, it generally automatically creates a `master` branch that tracks `origin/master`. That’s why `git push` and `git pull` work out of the box with no other arguments. However, you can set up other tracking branches if you wish — ones that don’t track branches on `origin` and don’t track the `master` branch. The simple case is the example you just saw, running `git checkout -b [branch] [remotename]/[branch]`. If you have Git version 1.6.2 or later, you can also use the `--track` shorthand: + + $ git checkout --track origin/serverfix + Branch serverfix set up to track remote branch serverfix from origin. + Switched to a new branch 'serverfix' + +To set up a local branch with a different name than the remote branch, you can easily use the first version with a different local branch name: + + $ git checkout -b sf origin/serverfix + Branch sf set up to track remote branch serverfix from origin. + Switched to a new branch 'sf' + +Now, your local branch `sf` will automatically push to and pull from `origin/serverfix`. + +### Deleting Remote Branches ### + +Suppose you’re done with a remote branch — say, you and your collaborators are finished with a feature and have merged it into your remote’s `master` branch (or whatever branch your stable codeline is in). You can delete a remote branch using the rather obtuse syntax `git push [remotename] :[branch]`. If you want to delete your `serverfix` branch from the server, you run the following: + + $ git push origin :serverfix + To git@github.com:schacon/simplegit.git + - [deleted] serverfix + +Boom. No more branch on your server. You may want to dog-ear this page, because you’ll need that command, and you’ll likely forget the syntax. A way to remember this command is by recalling the `git push [remotename] [localbranch]:[remotebranch]` syntax that we went over a bit earlier. If you leave off the `[localbranch]` portion, then you’re basically saying, “Take nothing on my side and make it be `[remotebranch]`.” + +## Rebasing ## + +In Git, there are two main ways to integrate changes from one branch into another: the `merge` and the `rebase`. In this section you’ll learn what rebasing is, how to do it, why it’s a pretty amazing tool, and in what cases you won’t want to use it. + +### The Basic Rebase ### + +If you go back to an earlier example from the Merge section (see Figure 3-27), you can see that you diverged your work and made commits on two different branches. + +Insert 18333fig0327.png +Figure 3-27. Your initial diverged commit history. + +The easiest way to integrate the branches, as we’ve already covered, is the `merge` command. It performs a three-way merge between the two latest branch snapshots (C3 and C4) and the most recent common ancestor of the two (C2), creating a new snapshot (and commit), as shown in Figure 3-28. + +Insert 18333fig0328.png +Figure 3-28. Merging a branch to integrate the diverged work history. + +However, there is another way: you can take the patch of the change that was introduced in C3 and reapply it on top of C4. In Git, this is called _rebasing_. With the `rebase` command, you can take all the changes that were committed on one branch and replay them on another one. + +In this example, you’d run the following: + + $ git checkout experiment + $ git rebase master + First, rewinding head to replay your work on top of it... + Applying: added staged command + +It works by going to the common ancestor of the two branches (the one you’re on and the one you’re rebasing onto), getting the diff introduced by each commit of the branch you’re on, saving those diffs to temporary files, resetting the current branch to the same commit as the branch you are rebasing onto, and finally applying each change in turn. Figure 3-29 illustrates this process. + +Insert 18333fig0329.png +Figure 3-29. Rebasing the change introduced in C3 onto C4. + +At this point, you can go back to the master branch and do a fast-forward merge (see Figure 3-30). + +Insert 18333fig0330.png +Figure 3-30. Fast-forwarding the master branch. + +Now, the snapshot pointed to by C3' is exactly the same as the one that was pointed to by C5 in the merge example. There is no difference in the end product of the integration, but rebasing makes for a cleaner history. If you examine the log of a rebased branch, it looks like a linear history: it appears that all the work happened in series, even when it originally happened in parallel. + +Often, you’ll do this to make sure your commits apply cleanly on a remote branch — perhaps in a project to which you’re trying to contribute but that you don’t maintain. In this case, you’d do your work in a branch and then rebase your work onto `origin/master` when you were ready to submit your patches to the main project. That way, the maintainer doesn’t have to do any integration work — just a fast-forward or a clean apply. + +Note that the snapshot pointed to by the final commit you end up with, whether it’s the last of the rebased commits for a rebase or the final merge commit after a merge, is the same snapshot — it’s only the history that is different. Rebasing replays changes from one line of work onto another in the order they were introduced, whereas merging takes the endpoints and merges them together. + +### More Interesting Rebases ### + +You can also have your rebase replay on something other than the rebase branch. Take a history like Figure 3-31, for example. You branched a topic branch (`server`) to add some server-side functionality to your project, and made a commit. Then, you branched off that to make the client-side changes (`client`) and committed a few times. Finally, you went back to your server branch and did a few more commits. + +Insert 18333fig0331.png +Figure 3-31. A history with a topic branch off another topic branch. + +Suppose you decide that you want to merge your client-side changes into your mainline for a release, but you want to hold off on the server-side changes until it’s tested further. You can take the changes on client that aren’t on server (C8 and C9) and replay them on your master branch by using the `--onto` option of `git rebase`: + + $ git rebase --onto master server client + +This basically says, “Check out the client branch, figure out the patches from the common ancestor of the `client` and `server` branches, and then replay them onto `master`.” It’s a bit complex; but the result, shown in Figure 3-32, is pretty cool. + +Insert 18333fig0332.png +Figure 3-32. Rebasing a topic branch off another topic branch. + +Now you can fast-forward your master branch (see Figure 3-33): + + $ git checkout master + $ git merge client + +Insert 18333fig0333.png +Figure 3-33. Fast-forwarding your master branch to include the client branch changes. + +Let’s say you decide to pull in your server branch as well. You can rebase the server branch onto the master branch without having to check it out first by running `git rebase [basebranch] [topicbranch]` — which checks out the topic branch (in this case, `server`) for you and replays it onto the base branch (`master`): + + $ git rebase master server + +This replays your `server` work on top of your `master` work, as shown in Figure 3-34. + +Insert 18333fig0334.png +Figure 3-34. Rebasing your server branch on top of your master branch. + +Then, you can fast-forward the base branch (`master`): + + $ git checkout master + $ git merge server + +You can remove the `client` and `server` branches because all the work is integrated and you don’t need them anymore, leaving your history for this entire process looking like Figure 3-35: + + $ git branch -d client + $ git branch -d server + +Insert 18333fig0335.png +Figure 3-35. Final commit history. + +### The Perils of Rebasing ### + +Ahh, but the bliss of rebasing isn’t without its drawbacks, which can be summed up in a single line: + +**Do not rebase commits that you have pushed to a public repository.** + +If you follow that guideline, you’ll be fine. If you don’t, people will hate you, and you’ll be scorned by friends and family. + +When you rebase stuff, you’re abandoning existing commits and creating new ones that are similar but different. If you push commits somewhere and others pull them down and base work on them, and then you rewrite those commits with `git rebase` and push them up again, your collaborators will have to re-merge their work and things will get messy when you try to pull their work back into yours. + +Let’s look at an example of how rebasing work that you’ve made public can cause problems. Suppose you clone from a central server and then do some work off that. Your commit history looks like Figure 3-36. + +Insert 18333fig0336.png +Figure 3-36. Clone a repository, and base some work on it. + +Now, someone else does more work that includes a merge, and pushes that work to the central server. You fetch them and merge the new remote branch into your work, making your history look something like Figure 3-37. + +Insert 18333fig0337.png +Figure 3-37. Fetch more commits, and merge them into your work. + +Next, the person who pushed the merged work decides to go back and rebase their work instead; they do a `git push --force` to overwrite the history on the server. You then fetch from that server, bringing down the new commits. + +Insert 18333fig0338.png +Figure 3-38. Someone pushes rebased commits, abandoning commits you’ve based your work on. + +At this point, you have to merge this work in again, even though you’ve already done so. Rebasing changes the SHA-1 hashes of these commits so to Git they look like new commits, when in fact you already have the C4 work in your history (see Figure 3-39). + +Insert 18333fig0339.png +Figure 3-39. You merge in the same work again into a new merge commit. + +You have to merge that work in at some point so you can keep up with the other developer in the future. After you do that, your commit history will contain both the C4 and C4' commits, which have different SHA-1 hashes but introduce the same work and have the same commit message. If you run a `git log` when your history looks like this, you’ll see two commits that have the same author date and message, which will be confusing. Furthermore, if you push this history back up to the server, you’ll reintroduce all those rebased commits to the central server, which can further confuse people. + +If you treat rebasing as a way to clean up and work with commits before you push them, and if you only rebase commits that have never been available publicly, then you’ll be fine. If you rebase commits that have already been pushed publicly, and people may have based work on those commits, then you may be in for some frustrating trouble. + +## Summary ## + +We’ve covered basic branching and merging in Git. You should feel comfortable creating and switching to new branches, switching between branches and merging local branches together. You should also be able to share your branches by pushing them to a shared server, working with others on shared branches and rebasing your branches before they are shared. diff --git a/fa/04-git-server/01-chapter4.markdown b/fa/04-git-server/01-chapter4.markdown new file mode 100644 index 000000000..538ff671d --- /dev/null +++ b/fa/04-git-server/01-chapter4.markdown @@ -0,0 +1,872 @@ +#Git روی سرور# + در این نقطه، شما باید توانایی انجام کارهای روزانه ای را که قصد دارید با Git انجام دهید، داشته باشید. بااین وجود، برای همکاری با دیگران در Git ، به یک مخزن خارجی Git نیاز دارید. + +At this point, you should be able to do most of the day-to-day tasks for which you’ll be using Git. However, in order to do any collaboration in Git, you’ll need to have a remote Git repository. Although you can technically push changes to and pull changes from individuals’ repositories, doing so is discouraged because you can fairly easily confuse what they’re working on if you’re not careful. Furthermore, you want your collaborators to be able to access the repository even if your computer is offline — having a more reliable common repository is often useful. Therefore, the preferred method for collaborating with someone is to set up an intermediate repository that you both have access to, and push to and pull from that. We’ll refer to this repository as a "Git server"; but you’ll notice that it generally takes a tiny amount of resources to host a Git repository, so you’ll rarely need to use an entire server for it. + +Running a Git server is simple. First, you choose which protocols you want your server to communicate with. The first section of this chapter will cover the available protocols and the pros and cons of each. The next sections will explain some typical setups using those protocols and how to get your server running with them. Last, we’ll go over a few hosted options, if you don’t mind hosting your code on someone else’s server and don’t want to go through the hassle of setting up and maintaining your own server. + +If you have no interest in running your own server, you can skip to the last section of the chapter to see some options for setting up a hosted account and then move on to the next chapter, where we discuss the various ins and outs of working in a distributed source control environment. + +A remote repository is generally a _bare repository_ — a Git repository that has no working directory. Because the repository is only used as a collaboration point, there is no reason to have a snapshot checked out on disk; it’s just the Git data. In the simplest terms, a bare repository is the contents of your project’s `.git` directory and nothing else. + +## The Protocols ## + +Git can use four major network protocols to transfer data: Local, Secure Shell (SSH), Git, and HTTP. Here we’ll discuss what they are and in what basic circumstances you would want (or not want) to use them. + +It’s important to note that with the exception of the HTTP protocols, all of these require Git to be installed and working on the server. + +### Local Protocol ### + +The most basic is the _Local protocol_, in which the remote repository is in another directory on disk. This is often used if everyone on your team has access to a shared filesystem such as an NFS mount, or in the less likely case that everyone logs in to the same computer. The latter wouldn’t be ideal, because all your code repository instances would reside on the same computer, making a catastrophic loss much more likely. + +If you have a shared mounted filesystem, then you can clone, push to, and pull from a local file-based repository. To clone a repository like this or to add one as a remote to an existing project, use the path to the repository as the URL. For example, to clone a local repository, you can run something like this: + + $ git clone /opt/git/project.git + +Or you can do this: + + $ git clone file:///opt/git/project.git + +Git operates slightly differently if you explicitly specify `file://` at the beginning of the URL. If you just specify the path, and the source and the destination are on the same filesystem, Git tries to hardlink the objects it needs. If they are not on the same filesystem, it will copy the objects it needs using the system's standard copying functionality. If you specify `file://`, Git fires up the processes that it normally uses to transfer data over a network which is generally a lot less efficient method of transferring the data. The main reason to specify the `file://` prefix is if you want a clean copy of the repository with extraneous references or objects left out — generally after an import from another version-control system or something similar (see Chapter 9 for maintenance tasks). We’ll use the normal path here because doing so is almost always faster. + +To add a local repository to an existing Git project, you can run something like this: + + $ git remote add local_proj /opt/git/project.git + +Then, you can push to and pull from that remote as though you were doing so over a network. + +#### The Pros #### + +The pros of file-based repositories are that they’re simple and they use existing file permissions and network access. If you already have a shared filesystem to which your whole team has access, setting up a repository is very easy. You stick the bare repository copy somewhere everyone has shared access to and set the read/write permissions as you would for any other shared directory. We’ll discuss how to export a bare repository copy for this purpose in the next section, “Getting Git on a Server.” + +This is also a nice option for quickly grabbing work from someone else’s working repository. If you and a co-worker are working on the same project and they want you to check something out, running a command like `git pull /home/john/project` is often easier than them pushing to a remote server and you pulling down. + +#### The Cons #### + +The cons of this method are that shared access is generally more difficult to set up and reach from multiple locations than basic network access. If you want to push from your laptop when you’re at home, you have to mount the remote disk, which can be difficult and slow compared to network-based access. + +It’s also important to mention that this isn’t necessarily the fastest option if you’re using a shared mount of some kind. A local repository is fast only if you have fast access to the data. A repository on NFS is often slower than the repository over SSH on the same server, allowing Git to run off local disks on each system. + +### The SSH Protocol ### + +Probably the most common transport protocol for Git is SSH. This is because SSH access to servers is already set up in most places — and if it isn’t, it’s easy to do. SSH is also the only network-based protocol that you can easily read from and write to. The other two network protocols (HTTP and Git) are generally read-only, so even if you have them available for the unwashed masses, you still need SSH for your own write commands. SSH is also an authenticated network protocol; and because it’s ubiquitous, it’s generally easy to set up and use. + +To clone a Git repository over SSH, you can specify ssh:// URL like this: + + $ git clone ssh://user@server/project.git + +Or you can use the shorter scp-like syntax for SSH protocol: + + $ git clone user@server:project.git + +You can also not specify a user, and Git assumes the user you’re currently logged in as. + +#### The Pros #### + +The pros of using SSH are many. First, you basically have to use it if you want authenticated write access to your repository over a network. Second, SSH is relatively easy to set up — SSH daemons are commonplace, many network admins have experience with them, and many OS distributions are set up with them or have tools to manage them. Next, access over SSH is secure — all data transfer is encrypted and authenticated. Last, like the Git and Local protocols, SSH is efficient, making the data as compact as possible before transferring it. + +#### The Cons #### + +The negative aspect of SSH is that you can’t serve anonymous access of your repository over it. People must have access to your machine over SSH to access it, even in a read-only capacity, which doesn’t make SSH access conducive to open source projects. If you’re using it only within your corporate network, SSH may be the only protocol you need to deal with. If you want to allow anonymous read-only access to your projects, you’ll have to set up SSH for you to push over but something else for others to pull over. + +### The Git Protocol ### + +Next is the Git protocol. This is a special daemon that comes packaged with Git; it listens on a dedicated port (9418) that provides a service similar to the SSH protocol, but with absolutely no authentication. In order for a repository to be served over the Git protocol, you must create the `git-daemon-export-ok` file — the daemon won’t serve a repository without that file in it — but other than that there is no security. Either the Git repository is available for everyone to clone or it isn’t. This means that there is generally no pushing over this protocol. You can enable push access; but given the lack of authentication, if you turn on push access, anyone on the internet who finds your project’s URL could push to your project. Suffice it to say that this is rare. + +#### The Pros #### + +The Git protocol is the fastest transfer protocol available. If you’re serving a lot of traffic for a public project or serving a very large project that doesn’t require user authentication for read access, it’s likely that you’ll want to set up a Git daemon to serve your project. It uses the same data-transfer mechanism as the SSH protocol but without the encryption and authentication overhead. + +#### The Cons #### + +The downside of the Git protocol is the lack of authentication. It’s generally undesirable for the Git protocol to be the only access to your project. Generally, you’ll pair it with SSH access for the few developers who have push (write) access and have everyone else use `git://` for read-only access. +It’s also probably the most difficult protocol to set up. It must run its own daemon, which is custom — we’ll look at setting one up in the “Gitosis” section of this chapter — it requires `xinetd` configuration or the like, which isn’t always a walk in the park. It also requires firewall access to port 9418, which isn’t a standard port that corporate firewalls always allow. Behind big corporate firewalls, this obscure port is commonly blocked. + +### The HTTP/S Protocol ### + +Last we have the HTTP protocol. The beauty of the HTTP or HTTPS protocol is the simplicity of setting it up. Basically, all you have to do is put the bare Git repository under your HTTP document root and set up a specific `post-update` hook, and you’re done (See Chapter 7 for details on Git hooks). At that point, anyone who can access the web server under which you put the repository can also clone your repository. To allow read access to your repository over HTTP, do something like this: + + $ cd /var/www/htdocs/ + $ git clone --bare /path/to/git_project gitproject.git + $ cd gitproject.git + $ mv hooks/post-update.sample hooks/post-update + $ chmod a+x hooks/post-update + +That’s all. The `post-update` hook that comes with Git by default runs the appropriate command (`git update-server-info`) to make HTTP fetching and cloning work properly. This command is run when you push to this repository over SSH; then, other people can clone via something like + + $ git clone http://example.com/gitproject.git + +In this particular case, we’re using the `/var/www/htdocs` path that is common for Apache setups, but you can use any static web server — just put the bare repository in its path. The Git data is served as basic static files (see Chapter 9 for details about exactly how it’s served). + +It’s possible to make Git push over HTTP as well, although that technique isn’t as widely used and requires you to set up complex WebDAV requirements. Because it’s rarely used, we won’t cover it in this book. If you’re interested in using the HTTP-push protocols, you can read about preparing a repository for this purpose at `http://www.kernel.org/pub/software/scm/git/docs/howto/setup-git-server-over-http.txt`. One nice thing about making Git push over HTTP is that you can use any WebDAV server, without specific Git features; so, you can use this functionality if your web-hosting provider supports WebDAV for writing updates to your web site. + +#### The Pros #### + +The upside of using the HTTP protocol is that it’s easy to set up. Running the handful of required commands gives you a simple way to give the world read access to your Git repository. It takes only a few minutes to do. The HTTP protocol also isn’t very resource intensive on your server. Because it generally uses a static HTTP server to serve all the data, a normal Apache server can serve thousands of files per second on average — it’s difficult to overload even a small server. + +You can also serve your repositories read-only over HTTPS, which means you can encrypt the content transfer; or you can go so far as to make the clients use specific signed SSL certificates. Generally, if you’re going to these lengths, it’s easier to use SSH public keys; but it may be a better solution in your specific case to use signed SSL certificates or other HTTP-based authentication methods for read-only access over HTTPS. + +Another nice thing is that HTTP is such a commonly used protocol that corporate firewalls are often set up to allow traffic through this port. + +#### The Cons #### + +The downside of serving your repository over HTTP is that it’s relatively inefficient for the client. It generally takes a lot longer to clone or fetch from the repository, and you often have a lot more network overhead and transfer volume over HTTP than with any of the other network protocols. Because it’s not as intelligent about transferring only the data you need — there is no dynamic work on the part of the server in these transactions — the HTTP protocol is often referred to as a _dumb_ protocol. For more information about the differences in efficiency between the HTTP protocol and the other protocols, see Chapter 9. + +## Getting Git on a Server ## + +In order to initially set up any Git server, you have to export an existing repository into a new bare repository — a repository that doesn’t contain a working directory. This is generally straightforward to do. +In order to clone your repository to create a new bare repository, you run the clone command with the `--bare` option. By convention, bare repository directories end in `.git`, like so: + + $ git clone --bare my_project my_project.git + Cloning into bare repository 'my_project.git'... + done. + +You should now have a copy of the Git directory data in your `my_project.git` directory. + +This is roughly equivalent to something like + + $ cp -Rf my_project/.git my_project.git + +There are a couple of minor differences in the configuration file; but for your purpose, this is close to the same thing. It takes the Git repository by itself, without a working directory, and creates a directory specifically for it alone. + +### Putting the Bare Repository on a Server ### + +Now that you have a bare copy of your repository, all you need to do is put it on a server and set up your protocols. Let’s say you’ve set up a server called `git.example.com` that you have SSH access to, and you want to store all your Git repositories under the `/opt/git` directory. You can set up your new repository by copying your bare repository over: + + $ scp -r my_project.git user@git.example.com:/opt/git + +At this point, other users who have SSH access to the same server which has read-access to the `/opt/git` directory can clone your repository by running + + $ git clone user@git.example.com:/opt/git/my_project.git + +If a user SSHs into a server and has write access to the `/opt/git/my_project.git` directory, they will also automatically have push access. Git will automatically add group write permissions to a repository properly if you run the `git init` command with the `--shared` option. + + $ ssh user@git.example.com + $ cd /opt/git/my_project.git + $ git init --bare --shared + +You see how easy it is to take a Git repository, create a bare version, and place it on a server to which you and your collaborators have SSH access. Now you’re ready to collaborate on the same project. + +It’s important to note that this is literally all you need to do to run a useful Git server to which several people have access — just add SSH-able accounts on a server, and stick a bare repository somewhere that all those users have read and write access to. You’re ready to go — nothing else needed. + +In the next few sections, you’ll see how to expand to more sophisticated setups. This discussion will include not having to create user accounts for each user, adding public read access to repositories, setting up web UIs, using the Gitosis tool, and more. However, keep in mind that to collaborate with a couple of people on a private project, all you _need_ is an SSH server and a bare repository. + +### Small Setups ### + +If you’re a small outfit or are just trying out Git in your organization and have only a few developers, things can be simple for you. One of the most complicated aspects of setting up a Git server is user management. If you want some repositories to be read-only to certain users and read/write to others, access and permissions can be a bit difficult to arrange. + +#### SSH Access #### + +If you already have a server to which all your developers have SSH access, it’s generally easiest to set up your first repository there, because you have to do almost no work (as we covered in the last section). If you want more complex access control type permissions on your repositories, you can handle them with the normal filesystem permissions of the operating system your server runs. + +If you want to place your repositories on a server that doesn’t have accounts for everyone on your team whom you want to have write access, then you must set up SSH access for them. We assume that if you have a server with which to do this, you already have an SSH server installed, and that’s how you’re accessing the server. + +There are a few ways you can give access to everyone on your team. The first is to set up accounts for everybody, which is straightforward but can be cumbersome. You may not want to run `adduser` and set temporary passwords for every user. + +A second method is to create a single 'git' user on the machine, ask every user who is to have write access to send you an SSH public key, and add that key to the `~/.ssh/authorized_keys` file of your new 'git' user. At that point, everyone will be able to access that machine via the 'git' user. This doesn’t affect the commit data in any way — the SSH user you connect as doesn’t affect the commits you’ve recorded. + +Another way to do it is to have your SSH server authenticate from an LDAP server or some other centralized authentication source that you may already have set up. As long as each user can get shell access on the machine, any SSH authentication mechanism you can think of should work. + +## Generating Your SSH Public Key ## + +That being said, many Git servers authenticate using SSH public keys. In order to provide a public key, each user in your system must generate one if they don’t already have one. This process is similar across all operating systems. +First, you should check to make sure you don’t already have a key. By default, a user’s SSH keys are stored in that user’s `~/.ssh` directory. You can easily check to see if you have a key already by going to that directory and listing the contents: + + $ cd ~/.ssh + $ ls + authorized_keys2 id_dsa known_hosts + config id_dsa.pub + +You’re looking for a pair of files named something and something.pub, where the something is usually `id_dsa` or `id_rsa`. The `.pub` file is your public key, and the other file is your private key. If you don’t have these files (or you don’t even have a `.ssh` directory), you can create them by running a program called `ssh-keygen`, which is provided with the SSH package on Linux/Mac systems and comes with the MSysGit package on Windows: + + $ ssh-keygen + Generating public/private rsa key pair. + Enter file in which to save the key (/Users/schacon/.ssh/id_rsa): + Enter passphrase (empty for no passphrase): + Enter same passphrase again: + Your identification has been saved in /Users/schacon/.ssh/id_rsa. + Your public key has been saved in /Users/schacon/.ssh/id_rsa.pub. + The key fingerprint is: + 43:c5:5b:5f:b1:f1:50:43:ad:20:a6:92:6a:1f:9a:3a schacon@agadorlaptop.local + +First it confirms where you want to save the key (`.ssh/id_rsa`), and then it asks twice for a passphrase, which you can leave empty if you don’t want to type a password when you use the key. + +Now, each user that does this has to send their public key to you or whoever is administrating the Git server (assuming you’re using an SSH server setup that requires public keys). All they have to do is copy the contents of the `.pub` file and e-mail it. The public keys look something like this: + + $ cat ~/.ssh/id_rsa.pub + ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAklOUpkDHrfHY17SbrmTIpNLTGK9Tjom/BWDSU + GPl+nafzlHDTYW7hdI4yZ5ew18JH4JW9jbhUFrviQzM7xlELEVf4h9lFX5QVkbPppSwg0cda3 + Pbv7kOdJ/MTyBlWXFCR+HAo3FXRitBqxiX1nKhXpHAZsMciLq8V6RjsNAQwdsdMFvSlVK/7XA + t3FaoJoAsncM1Q9x5+3V0Ww68/eIFmb1zuUFljQJKprrX88XypNDvjYNby6vw/Pb0rwert/En + mZ+AW4OZPnTPI89ZPmVMLuayrD2cE86Z/il8b+gw3r3+1nKatmIkjn2so1d01QraTlMqVSsbx + NrRFi9wrf+M7Q== schacon@agadorlaptop.local + +For a more in-depth tutorial on creating an SSH key on multiple operating systems, see the GitHub guide on SSH keys at `http://github.com/guides/providing-your-ssh-key`. + +## Setting Up the Server ## + +Let’s walk through setting up SSH access on the server side. In this example, you’ll use the `authorized_keys` method for authenticating your users. We also assume you’re running a standard Linux distribution like Ubuntu. First, you create a 'git' user and a `.ssh` directory for that user. + + $ sudo adduser git + $ su git + $ cd + $ mkdir .ssh + +Next, you need to add some developer SSH public keys to the `authorized_keys` file for that user. Let’s assume you’ve received a few keys by e-mail and saved them to temporary files. Again, the public keys look something like this: + + $ cat /tmp/id_rsa.john.pub + ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCB007n/ww+ouN4gSLKssMxXnBOvf9LGt4L + ojG6rs6hPB09j9R/T17/x4lhJA0F3FR1rP6kYBRsWj2aThGw6HXLm9/5zytK6Ztg3RPKK+4k + Yjh6541NYsnEAZuXz0jTTyAUfrtU3Z5E003C4oxOj6H0rfIF1kKI9MAQLMdpGW1GYEIgS9Ez + Sdfd8AcCIicTDWbqLAcU4UpkaX8KyGlLwsNuuGztobF8m72ALC/nLF6JLtPofwFBlgc+myiv + O7TCUSBdLQlgMVOFq1I2uPWQOkOWQAHukEOmfjy2jctxSDBQ220ymjaNsHT4kgtZg2AYYgPq + dAv8JggJICUvax2T9va5 gsg-keypair + +You just append them to your `authorized_keys` file: + + $ cat /tmp/id_rsa.john.pub >> ~/.ssh/authorized_keys + $ cat /tmp/id_rsa.josie.pub >> ~/.ssh/authorized_keys + $ cat /tmp/id_rsa.jessica.pub >> ~/.ssh/authorized_keys + +Key-based SSH authentication usually enforces security by requiring restricted rights on the involved files. To prevent SSH from refusing to work, type this: + + $ chmod -R go= ~/.ssh + +Now, you can set up an empty repository for your users by running `git init` with the `--bare` option, which initializes the repository without a working directory: + + $ cd /opt/git + $ mkdir project.git + $ cd project.git + $ git --bare init + +Then, John, Josie, or Jessica can push the first version of their project into that repository by adding it as a remote and pushing up a branch. Note that someone must shell onto the machine and create a bare repository every time you want to add a project. Let’s use `gitserver` as the hostname of the server on which you’ve set up your 'git' user and repository. If you’re running it internally, and you set up DNS for `gitserver` to point to that server, then you can use the commands pretty much as is: + + # on Johns computer + $ cd myproject + $ git init + $ git add . + $ git commit -m 'initial commit' + $ git remote add origin git@gitserver:/opt/git/project.git + $ git push origin master + +At this point, the others can clone it down and push changes back up just as easily: + + $ git clone git@gitserver:/opt/git/project.git + $ cd project + $ vim README + $ git commit -am 'fix for the README file' + $ git push origin master + +With this method, you can quickly get a read/write Git server up and running for a handful of developers. + +As an extra precaution, you can easily restrict the 'git' user to only doing Git activities with a limited shell tool called `git-shell` that comes with Git. If you set this as your 'git' user’s login shell, then the 'git' user can’t have normal shell access to your server. To use this, specify `git-shell` instead of bash or csh for your user’s login shell. To do so, you’ll likely have to edit your `/etc/passwd` file: + + $ sudo vim /etc/passwd + +At the bottom, you should find a line that looks something like this: + + git:x:1000:1000::/home/git:/bin/sh + +Change `/bin/sh` to `/usr/bin/git-shell` (or run `which git-shell` to see where it’s installed). The line should look something like this: + + git:x:1000:1000::/home/git:/usr/bin/git-shell + +Now, the 'git' user can only use the SSH connection to push and pull Git repositories and can’t shell onto the machine. If you try, you’ll see a login rejection like this: + + $ ssh git@gitserver + fatal: What do you think I am? A shell? + Connection to gitserver closed. + +## Public Access ## + +What if you want anonymous read access to your project? Perhaps instead of hosting an internal private project, you want to host an open source project. Or maybe you have a bunch of automated build servers or continuous integration servers that change a lot, and you don’t want to have to generate SSH keys all the time — you just want to add simple anonymous read access. + +Probably the simplest way for smaller setups is to run a static web server with its document root where your Git repositories are, and then enable that `post-update` hook we mentioned in the first section of this chapter. Let’s work from the previous example. Say you have your repositories in the `/opt/git` directory, and an Apache server is running on your machine. Again, you can use any web server for this; but as an example, we’ll demonstrate some basic Apache configurations that should give you an idea of what you might need. + +First you need to enable the hook: + + $ cd project.git + $ mv hooks/post-update.sample hooks/post-update + $ chmod a+x hooks/post-update + +What does this `post-update` hook do? It looks basically like this: + + $ cat .git/hooks/post-update + #!/bin/sh + # + # An example hook script to prepare a packed repository for use over + # dumb transports. + # + # To enable this hook, rename this file to "post-update". + # + + exec git-update-server-info + +This means that when you push to the server via SSH, Git will run this command to update the files needed for HTTP fetching. + +Next, you need to add a VirtualHost entry to your Apache configuration with the document root as the root directory of your Git projects. Here, we’re assuming that you have wildcard DNS set up to send `*.gitserver` to whatever box you’re using to run all this: + + + ServerName git.gitserver + DocumentRoot /opt/git + + Order allow, deny + allow from all + + + +You’ll also need to set the Unix user group of the `/opt/git` directories to `www-data` so your web server can read-access the repositories, because the Apache instance running the CGI script will (by default) be running as that user: + + $ chgrp -R www-data /opt/git + +When you restart Apache, you should be able to clone your repositories under that directory by specifying the URL for your project: + + $ git clone http://git.gitserver/project.git + +This way, you can set up HTTP-based read access to any of your projects for a fair number of users in a few minutes. Another simple option for public unauthenticated access is to start a Git daemon, although that requires you to daemonize the process - we’ll cover this option in the next section, if you prefer that route. + +## GitWeb ## + +Now that you have basic read/write and read-only access to your project, you may want to set up a simple web-based visualizer. Git comes with a CGI script called GitWeb that is commonly used for this. You can see GitWeb in use at sites like `http://git.kernel.org` (see Figure 4-1). + +Insert 18333fig0401.png +Figure 4-1. The GitWeb web-based user interface. + +If you want to check out what GitWeb would look like for your project, Git comes with a command to fire up a temporary instance if you have a lightweight server on your system like `lighttpd` or `webrick`. On Linux machines, `lighttpd` is often installed, so you may be able to get it to run by typing `git instaweb` in your project directory. If you’re running a Mac, Leopard comes preinstalled with Ruby, so `webrick` may be your best bet. To start `instaweb` with a non-lighttpd handler, you can run it with the `--httpd` option. + + $ git instaweb --httpd=webrick + [2009-02-21 10:02:21] INFO WEBrick 1.3.1 + [2009-02-21 10:02:21] INFO ruby 1.8.6 (2008-03-03) [universal-darwin9.0] + +That starts up an HTTPD server on port 1234 and then automatically starts a web browser that opens on that page. It’s pretty easy on your part. When you’re done and want to shut down the server, you can run the same command with the `--stop` option: + + $ git instaweb --httpd=webrick --stop + +If you want to run the web interface on a server all the time for your team or for an open source project you’re hosting, you’ll need to set up the CGI script to be served by your normal web server. Some Linux distributions have a `gitweb` package that you may be able to install via `apt` or `yum`, so you may want to try that first. We’ll walk though installing GitWeb manually very quickly. First, you need to get the Git source code, which GitWeb comes with, and generate the custom CGI script: + + $ git clone git://git.kernel.org/pub/scm/git/git.git + $ cd git/ + $ make GITWEB_PROJECTROOT="/opt/git" \ + prefix=/usr gitweb + $ sudo cp -Rf gitweb /var/www/ + +Notice that you have to tell the command where to find your Git repositories with the `GITWEB_PROJECTROOT` variable. Now, you need to make Apache use CGI for that script, for which you can add a VirtualHost: + + + ServerName gitserver + DocumentRoot /var/www/gitweb + + Options ExecCGI +FollowSymLinks +SymLinksIfOwnerMatch + AllowOverride All + order allow,deny + Allow from all + AddHandler cgi-script cgi + DirectoryIndex gitweb.cgi + + + +Again, GitWeb can be served with any CGI capable web server; if you prefer to use something else, it shouldn’t be difficult to set up. At this point, you should be able to visit `http://gitserver/` to view your repositories online, and you can use `http://git.gitserver` to clone and fetch your repositories over HTTP. + +## Gitosis ## + +Keeping all users’ public keys in the `authorized_keys` file for access works well only for a while. When you have hundreds of users, it’s much more of a pain to manage that process. You have to shell onto the server each time, and there is no access control — everyone in the file has read and write access to every project. + +At this point, you may want to turn to a widely used software project called Gitosis. Gitosis is basically a set of scripts that help you manage the `authorized_keys` file as well as implement some simple access controls. The really interesting part is that the UI for this tool for adding people and determining access isn’t a web interface but a special Git repository. You set up the information in that project; and when you push it, Gitosis reconfigures the server based on that, which is cool. + +Installing Gitosis isn’t the simplest task ever, but it’s not too difficult. It’s easiest to use a Linux server for it — these examples use a stock Ubuntu 8.10 server. + +Gitosis requires some Python tools, so first you have to install the Python setuptools package, which Ubuntu provides as python-setuptools: + + $ apt-get install python-setuptools + +Next, you clone and install Gitosis from the project’s main site: + + $ git clone https://github.com/tv42/gitosis.git + $ cd gitosis + $ sudo python setup.py install + +That installs a couple of executables that Gitosis will use. Next, Gitosis wants to put its repositories under `/home/git`, which is fine. But you have already set up your repositories in `/opt/git`, so instead of reconfiguring everything, you create a symlink: + + $ ln -s /opt/git /home/git/repositories + +Gitosis is going to manage your keys for you, so you need to remove the current file, re-add the keys later, and let Gitosis control the `authorized_keys` file automatically. For now, move the `authorized_keys` file out of the way: + + $ mv /home/git/.ssh/authorized_keys /home/git/.ssh/ak.bak + +Next you need to turn your shell back on for the 'git' user, if you changed it to the `git-shell` command. People still won’t be able to log in, but Gitosis will control that for you. So, let’s change this line in your `/etc/passwd` file + + git:x:1000:1000::/home/git:/usr/bin/git-shell + +back to this: + + git:x:1000:1000::/home/git:/bin/sh + +Now it’s time to initialize Gitosis. You do this by running the `gitosis-init` command with your personal public key. If your public key isn’t on the server, you’ll have to copy it there: + + $ sudo -H -u git gitosis-init < /tmp/id_dsa.pub + Initialized empty Git repository in /opt/git/gitosis-admin.git/ + Reinitialized existing Git repository in /opt/git/gitosis-admin.git/ + +This lets the user with that key modify the main Git repository that controls the Gitosis setup. Next, you have to manually set the execute bit on the `post-update` script for your new control repository. + + $ sudo chmod 755 /opt/git/gitosis-admin.git/hooks/post-update + +You’re ready to roll. If you’re set up correctly, you can try to SSH into your server as the user for which you added the public key to initialize Gitosis. You should see something like this: + + $ ssh git@gitserver + PTY allocation request failed on channel 0 + ERROR:gitosis.serve.main:Need SSH_ORIGINAL_COMMAND in environment. + Connection to gitserver closed. + +That means Gitosis recognized you but shut you out because you’re not trying to do any Git commands. So, let’s do an actual Git command — you’ll clone the Gitosis control repository: + + # on your local computer + $ git clone git@gitserver:gitosis-admin.git + +Now you have a directory named `gitosis-admin`, which has two major parts: + + $ cd gitosis-admin + $ find . + ./gitosis.conf + ./keydir + ./keydir/scott.pub + +The `gitosis.conf` file is the control file you use to specify users, repositories, and permissions. The `keydir` directory is where you store the public keys of all the users who have any sort of access to your repositories — one file per user. The name of the file in `keydir` (in the previous example, `scott.pub`) will be different for you — Gitosis takes that name from the description at the end of the public key that was imported with the `gitosis-init` script. + +If you look at the `gitosis.conf` file, it should only specify information about the `gitosis-admin` project that you just cloned: + + $ cat gitosis.conf + [gitosis] + + [group gitosis-admin] + members = scott + writable = gitosis-admin + +It shows you that the 'scott' user — the user with whose public key you initialized Gitosis — is the only one who has access to the `gitosis-admin` project. + +Now, let’s add a new project for you. You’ll add a new section called `mobile` where you’ll list the developers on your mobile team and projects that those developers need access to. Because 'scott' is the only user in the system right now, you’ll add him as the only member, and you’ll create a new project called `iphone_project` to start on: + + [group mobile] + members = scott + writable = iphone_project + +Whenever you make changes to the `gitosis-admin` project, you have to commit the changes and push them back up to the server in order for them to take effect: + + $ git commit -am 'add iphone_project and mobile group' + [master 8962da8] add iphone_project and mobile group + 1 file changed, 4 insertions(+) + $ git push origin master + Counting objects: 5, done. + Compressing objects: 100% (3/3), done. + Writing objects: 100% (3/3), 272 bytes | 0 bytes/s, done. + Total 3 (delta 0), reused 0 (delta 0) + To git@gitserver:gitosis-admin.git + fb27aec..8962da8 master -> master + +You can make your first push to the new `iphone_project` project by adding your server as a remote to your local version of the project and pushing. You no longer have to manually create a bare repository for new projects on the server — Gitosis creates them automatically when it sees the first push: + + $ git remote add origin git@gitserver:iphone_project.git + $ git push origin master + Initialized empty Git repository in /opt/git/iphone_project.git/ + Counting objects: 3, done. + Writing objects: 100% (3/3), 230 bytes | 0 bytes/s, done. + Total 3 (delta 0), reused 0 (delta 0) + To git@gitserver:iphone_project.git + * [new branch] master -> master + +Notice that you don’t need to specify the path (in fact, doing so won’t work), just a colon and then the name of the project — Gitosis finds it for you. + +You want to work on this project with your friends, so you’ll have to re-add their public keys. But instead of appending them manually to the `~/.ssh/authorized_keys` file on your server, you’ll add them, one key per file, into the `keydir` directory. How you name the keys determines how you refer to the users in the `gitosis.conf` file. Let’s re-add the public keys for John, Josie, and Jessica: + + $ cp /tmp/id_rsa.john.pub keydir/john.pub + $ cp /tmp/id_rsa.josie.pub keydir/josie.pub + $ cp /tmp/id_rsa.jessica.pub keydir/jessica.pub + +Now you can add them all to your 'mobile' team so they have read and write access to `iphone_project`: + + [group mobile] + members = scott john josie jessica + writable = iphone_project + +After you commit and push that change, all four users will be able to read from and write to that project. + +Gitosis has simple access controls as well. If you want John to have only read access to this project, you can do this instead: + + [group mobile] + members = scott josie jessica + writable = iphone_project + + [group mobile_ro] + members = john + readonly = iphone_project + +Now John can clone the project and get updates, but Gitosis won’t allow him to push back up to the project. You can create as many of these groups as you want, each containing different users and projects. You can also specify another group as one of the members (using `@` as prefix), to inherit all of its members automatically: + + [group mobile_committers] + members = scott josie jessica + + [group mobile] + members = @mobile_committers + writable = iphone_project + + [group mobile_2] + members = @mobile_committers john + writable = another_iphone_project + +If you have any issues, it may be useful to add `loglevel=DEBUG` under the `[gitosis]` section. If you’ve lost push access by pushing a messed-up configuration, you can manually fix the file on the server under `/home/git/.gitosis.conf` — the file from which Gitosis reads its info. A push to the project takes the `gitosis.conf` file you just pushed up and sticks it there. If you edit that file manually, it remains like that until the next successful push to the `gitosis-admin` project. + +## Gitolite ## + +This section serves as a quick introduction to Gitolite, and provides basic installation and setup instructions. It cannot, however, replace the enormous amount of [documentation][gltoc] that Gitolite comes with. There may also be occasional changes to this section itself, so you may also want to look at the latest version [here][gldpg]. + +[gldpg]: http://sitaramc.github.com/gitolite/progit.html +[gltoc]: http://sitaramc.github.com/gitolite/master-toc.html + +Gitolite is an authorization layer on top of Git, relying on `sshd` or `httpd` for authentication. (Recap: authentication is identifying who the user is, authorization is deciding if he is allowed to do what he is attempting to). + +Gitolite allows you to specify permissions not just by repository, but also by branch or tag names within each repository. That is, you can specify that certain people (or groups of people) can only push certain "refs" (branches or tags) but not others. + +### Installing ### + +Installing Gitolite is very easy, even if you don’t read the extensive documentation that comes with it. You need an account on a Unix server of some kind. You do not need root access, assuming Git, Perl, and an OpenSSH compatible SSH server are already installed. In the examples below, we will use the `git` account on a host called `gitserver`. + +Gitolite is somewhat unusual as far as "server" software goes — access is via SSH, and so every userid on the server is a potential "gitolite host". We will describe the simplest install method in this article; for the other methods please see the documentation. + +To begin, create a user called `git` on your server and login to this user. Copy your SSH public key (a file called `~/.ssh/id_rsa.pub` if you did a plain `ssh-keygen` with all the defaults) from your workstation, renaming it to `.pub` (we'll use `scott.pub` in our examples). Then run these commands: + + $ git clone git://github.com/sitaramc/gitolite + $ gitolite/install -ln + # assumes $HOME/bin exists and is in your $PATH + $ gitolite setup -pk $HOME/scott.pub + +That last command creates new Git repository called `gitolite-admin` on the server. + +Finally, back on your workstation, run `git clone git@gitserver:gitolite-admin`. And you’re done! Gitolite has now been installed on the server, and you now have a brand new repository called `gitolite-admin` in your workstation. You administer your Gitolite setup by making changes to this repository and pushing. + +### Customising the Install ### + +While the default, quick, install works for most people, there are some ways to customise the install if you need to. Some changes can be made simply by editing the rc file, but if that is not sufficient, there’s documentation on customising Gitolite. + +### Config File and Access Control Rules ### + +Once the install is done, you switch to the `gitolite-admin` clone you just made on your workstation, and poke around to see what you got: + + $ cd ~/gitolite-admin/ + $ ls + conf/ keydir/ + $ find conf keydir -type f + conf/gitolite.conf + keydir/scott.pub + $ cat conf/gitolite.conf + + repo gitolite-admin + RW+ = scott + + repo testing + RW+ = @all + +Notice that "scott" (the name of the pubkey in the `gitolite setup` command you used earlier) has read-write permissions on the `gitolite-admin` repository as well as a public key file of the same name. + +Adding users is easy. To add a user called "alice", obtain her public key, name it `alice.pub`, and put it in the `keydir` directory of the clone of the `gitolite-admin` repo you just made on your workstation. Add, commit, and push the change, and the user has been added. + +The config file syntax for Gitolite is well documented, so we’ll only mention some highlights here. + +You can group users or repos for convenience. The group names are just like macros; when defining them, it doesn’t even matter whether they are projects or users; that distinction is only made when you *use* the "macro". + + @oss_repos = linux perl rakudo git gitolite + @secret_repos = fenestra pear + + @admins = scott + @interns = ashok + @engineers = sitaram dilbert wally alice + @staff = @admins @engineers @interns + +You can control permissions at the "ref" level. In the following example, interns can only push the "int" branch. Engineers can push any branch whose name starts with "eng-", and tags that start with "rc" followed by a digit. And the admins can do anything (including rewind) to any ref. + + repo @oss_repos + RW int$ = @interns + RW eng- = @engineers + RW refs/tags/rc[0-9] = @engineers + RW+ = @admins + +The expression after the `RW` or `RW+` is a regular expression (regex) that the refname (ref) being pushed is matched against. So we call it a "refex"! Of course, a refex can be far more powerful than shown here, so don’t overdo it if you’re not comfortable with Perl regexes. + +Also, as you probably guessed, Gitolite prefixes `refs/heads/` as a syntactic convenience if the refex does not begin with `refs/`. + +An important feature of the config file’s syntax is that all the rules for a repository need not be in one place. You can keep all the common stuff together, like the rules for all `oss_repos` shown above, then add specific rules for specific cases later on, like so: + + repo gitolite + RW+ = sitaram + +That rule will just get added to the ruleset for the `gitolite` repository. + +At this point you might be wondering how the access control rules are actually applied, so let’s go over that briefly. + +There are two levels of access control in Gitolite. The first is at the repository level; if you have read (or write) access to *any* ref in the repository, then you have read (or write) access to the repository. This is the only access control that Gitosis had. + +The second level, applicable only to "write" access, is by branch or tag within a repository. The username, the access being attempted (`W` or `+`), and the refname being updated are known. The access rules are checked in order of appearance in the config file, looking for a match for this combination (but remember that the refname is regex-matched, not merely string-matched). If a match is found, the push succeeds. A fallthrough results in access being denied. + +### Advanced Access Control with "deny" rules ### + +So far, we’ve only seen permissions to be one of `R`, `RW`, or `RW+`. However, Gitolite allows another permission: `-`, standing for "deny". This gives you a lot more power, at the expense of some complexity, because now fallthrough is not the *only* way for access to be denied, so the *order of the rules now matters*! + +Let us say, in the situation above, we want engineers to be able to rewind any branch *except* master and integ. Here’s how to do that: + + RW master integ = @engineers + - master integ = @engineers + RW+ = @engineers + +Again, you simply follow the rules top down until you hit a match for your access mode, or a deny. Non-rewind push to master or integ is allowed by the first rule. A rewind push to those refs does not match the first rule, drops down to the second, and is therefore denied. Any push (rewind or non-rewind) to refs other than master or integ won’t match the first two rules anyway, and the third rule allows it. + +### Restricting pushes by files changed ### + +In addition to restricting what branches a user can push changes to, you can also restrict what files they are allowed to touch. For example, perhaps the Makefile (or some other program) is really not supposed to be changed by just anyone, because a lot of things depend on it or would break if the changes are not done *just right*. You can tell Gitolite: + + repo foo + RW = @junior_devs @senior_devs + + - VREF/NAME/Makefile = @junior_devs + +Users who are migrating from the older Gitolite should note that there is a significant change in behaviour with regard to this feature; please see the migration guide for details. + +### Personal Branches ### + +Gitolite also has a feature called "personal branches" (or rather, "personal branch namespace") that can be very useful in a corporate environment. + +A lot of code exchange in the Git world happens by "please pull" requests. In a corporate environment, however, unauthenticated access is a no-no, and a developer workstation cannot do authentication, so you have to push to the central server and ask someone to pull from there. + +This would normally cause the same branch name clutter as in a centralised VCS, plus setting up permissions for this becomes a chore for the admin. + +Gitolite lets you define a "personal" or "scratch" namespace prefix for each developer (for example, `refs/personal//*`); please see the documentation for details. + +### "Wildcard" repositories ### + +Gitolite allows you to specify repositories with wildcards (actually Perl regexes), like, for example `assignments/s[0-9][0-9]/a[0-9][0-9]`, to pick a random example. It also allows you to assign a new permission mode (`C`) which enables users to create repositories based on such wild cards, automatically assigns ownership to the specific user who created it, allows him/her to hand out `R` and `RW` permissions to other users to collaborate, etc. Again, please see the documentation for details. + +### Other Features ### + +We’ll round off this discussion with a sampling of other features, all of which, and many more, are described in great detail in the documentation. + +**Logging**: Gitolite logs all successful accesses. If you were somewhat relaxed about giving people rewind permissions (`RW+`) and some kid blew away `master`, the log file is a life saver, in terms of easily and quickly finding the SHA that got hosed. + +**Access rights reporting**: Another convenient feature is what happens when you try and just ssh to the server. Gitolite shows you what repos you have access to, and what that access may be. Here’s an example: + + hello scott, this is git@git running gitolite3 v3.01-18-g9609868 on git 1.7.4.4 + + R anu-wsd + R entrans + R W git-notes + R W gitolite + R W gitolite-admin + R indic_web_input + R shreelipi_converter + +**Delegation**: For really large installations, you can delegate responsibility for groups of repositories to various people and have them manage those pieces independently. This reduces the load on the main admin, and makes him less of a bottleneck. + +**Mirroring**: Gitolite can help you maintain multiple mirrors, and switch between them easily if the primary server goes down. + +## Git Daemon ## + +For public, unauthenticated read access to your projects, you’ll want to move past the HTTP protocol and start using the Git protocol. The main reason is speed. The Git protocol is far more efficient and thus faster than the HTTP protocol, so using it will save your users time. + +Again, this is for unauthenticated read-only access. If you’re running this on a server outside your firewall, it should only be used for projects that are publicly visible to the world. If the server you’re running it on is inside your firewall, you might use it for projects that a large number of people or computers (continuous integration or build servers) have read-only access to, when you don’t want to have to add an SSH key for each. + +In any case, the Git protocol is relatively easy to set up. Basically, you need to run this command in a daemonized manner: + + git daemon --reuseaddr --base-path=/opt/git/ /opt/git/ + +`--reuseaddr` allows the server to restart without waiting for old connections to time out, the `--base-path` option allows people to clone projects without specifying the entire path, and the path at the end tells the Git daemon where to look for repositories to export. If you’re running a firewall, you’ll also need to punch a hole in it at port 9418 on the box you’re setting this up on. + +You can daemonize this process a number of ways, depending on the operating system you’re running. On an Ubuntu machine, you use an Upstart script. So, in the following file + + /etc/event.d/local-git-daemon + +you put this script: + + start on startup + stop on shutdown + exec /usr/bin/git daemon \ + --user=git --group=git \ + --reuseaddr \ + --base-path=/opt/git/ \ + /opt/git/ + respawn + +For security reasons, it is strongly encouraged to have this daemon run as a user with read-only permissions to the repositories — you can easily do this by creating a new user 'git-ro' and running the daemon as them. For the sake of simplicity we’ll simply run it as the same 'git' user that Gitosis is running as. + +When you restart your machine, your Git daemon will start automatically and respawn if it goes down. To get it running without having to reboot, you can run this: + + initctl start local-git-daemon + +On other systems, you may want to use `xinetd`, a script in your `sysvinit` system, or something else — as long as you get that command daemonized and watched somehow. + +Next, you have to tell your Gitosis server which repositories to allow unauthenticated Git server-based access to. If you add a section for each repository, you can specify the ones from which you want your Git daemon to allow reading. If you want to allow Git protocol access for the `iphone_project`, you add this to the end of the `gitosis.conf` file: + + [repo iphone_project] + daemon = yes + +When that is committed and pushed up, your running daemon should start serving requests for the project to anyone who has access to port 9418 on your server. + +If you decide not to use Gitosis, but you want to set up a Git daemon, you’ll have to run this on each project you want the Git daemon to serve: + + $ cd /path/to/project.git + $ touch git-daemon-export-ok + +The presence of that file tells Git that it’s OK to serve this project without authentication. + +Gitosis can also control which projects GitWeb shows. First, you need to add something like the following to the `/etc/gitweb.conf` file: + + $projects_list = "/home/git/gitosis/projects.list"; + $projectroot = "/home/git/repositories"; + $export_ok = "git-daemon-export-ok"; + @git_base_url_list = ('git://gitserver'); + +You can control which projects GitWeb lets users browse by adding or removing a `gitweb` setting in the Gitosis configuration file. For instance, if you want the `iphone_project` to show up on GitWeb, you make the `repo` setting look like this: + + [repo iphone_project] + daemon = yes + gitweb = yes + +Now, if you commit and push the project, GitWeb will automatically start showing the `iphone_project`. + +## Hosted Git ## + +If you don’t want to go through all of the work involved in setting up your own Git server, you have several options for hosting your Git projects on an external dedicated hosting site. Doing so offers a number of advantages: a hosting site is generally quick to set up and easy to start projects on, and no server maintenance or monitoring is involved. Even if you set up and run your own server internally, you may still want to use a public hosting site for your open source code — it’s generally easier for the open source community to find and help you with. + +These days, you have a huge number of hosting options to choose from, each with different advantages and disadvantages. To see an up-to-date list, check out the following page: + + https://git.wiki.kernel.org/index.php/GitHosting + +Because we can’t cover all of them, and because I happen to work at one of them, we’ll use this section to walk through setting up an account and creating a new project at GitHub. This will give you an idea of what is involved. + +GitHub is by far the largest open source Git hosting site and it’s also one of the very few that offers both public and private hosting options so you can keep your open source and private commercial code in the same place. In fact, we used GitHub to privately collaborate on this book. + +### GitHub ### + +GitHub is slightly different than most code-hosting sites in the way that it namespaces projects. Instead of being primarily based on the project, GitHub is user-centric. That means when I host my `grit` project on GitHub, you won’t find it at `github.com/grit` but instead at `github.com/schacon/grit`. There is no canonical version of any project, which allows a project to move from one user to another seamlessly if the first author abandons the project. + +GitHub is also a commercial company that charges for accounts that maintain private repositories, but anyone can quickly get a free account to host as many open source projects as they want. We’ll quickly go over how that is done. + +### Setting Up a User Account ### + +The first thing you need to do is set up a free user account. If you visit the "Plans and pricing" page at `https://github.com/pricing` and click the "Sign Up" button on the Free account (see Figure 4-2), you’re taken to the signup page. + +Insert 18333fig0402.png +Figure 4-2. The GitHub plan page. + +Here you must choose a username that isn’t yet taken in the system and enter an e-mail address that will be associated with the account and a password (see Figure 4-3). + +Insert 18333fig0403.png +Figure 4-3. The GitHub user signup form. + +If you have it available, this is a good time to add your public SSH key as well. We covered how to generate a new key earlier, in the "Simple Setups" section. Take the contents of the public key of that pair, and paste it into the SSH Public Key text box. Clicking the "explain ssh keys" link takes you to detailed instructions on how to do so on all major operating systems. +Clicking the "I agree, sign me up" button takes you to your new user dashboard (see Figure 4-4). + +Insert 18333fig0404.png +Figure 4-4. The GitHub user dashboard. + +Next you can create a new repository. + +### Creating a New Repository ### + +Start by clicking the "create a new one" link next to Your Repositories on the user dashboard. You’re taken to the Create a New Repository form (see Figure 4-5). + +Insert 18333fig0405.png +Figure 4-5. Creating a new repository on GitHub. + +All you really have to do is provide a project name, but you can also add a description. When that is done, click the "Create Repository" button. Now you have a new repository on GitHub (see Figure 4-6). + +Insert 18333fig0406.png +Figure 4-6. GitHub project header information. + +Since you have no code there yet, GitHub will show you instructions for how create a brand-new project, push an existing Git project up, or import a project from a public Subversion repository (see Figure 4-7). + +Insert 18333fig0407.png +Figure 4-7. Instructions for a new repository. + +These instructions are similar to what we’ve already gone over. To initialize a project if it isn’t already a Git project, you use + + $ git init + $ git add . + $ git commit -m 'initial commit' + +When you have a Git repository locally, add GitHub as a remote and push up your master branch: + + $ git remote add origin git@github.com:testinguser/iphone_project.git + $ git push origin master + +Now your project is hosted on GitHub, and you can give the URL to anyone you want to share your project with. In this case, it’s `http://github.com/testinguser/iphone_project`. You can also see from the header on each of your project’s pages that you have two Git URLs (see Figure 4-8). + +Insert 18333fig0408.png +Figure 4-8. Project header with a public URL and a private URL. + +The Public Clone URL is a public, read-only Git URL over which anyone can clone the project. Feel free to give out that URL and post it on your web site or what have you. + +The Your Clone URL is a read/write SSH-based URL that you can read or write over only if you connect with the SSH private key associated with the public key you uploaded for your user. When other users visit this project page, they won’t see that URL—only the public one. + +### Importing from Subversion ### + +If you have an existing public Subversion project that you want to import into Git, GitHub can often do that for you. At the bottom of the instructions page is a link to a Subversion import. If you click it, you see a form with information about the import process and a text box where you can paste in the URL of your public Subversion project (see Figure 4-9). + +Insert 18333fig0409.png +Figure 4-9. Subversion importing interface. + +If your project is very large, nonstandard, or private, this process probably won’t work for you. In Chapter 7, you’ll learn how to do more complicated manual project imports. + +### Adding Collaborators ### + +Let’s add the rest of the team. If John, Josie, and Jessica all sign up for accounts on GitHub, and you want to give them push access to your repository, you can add them to your project as collaborators. Doing so will allow pushes from their public keys to work. + +Click the "edit" button in the project header or the Admin tab at the top of the project to reach the Admin page of your GitHub project (see Figure 4-10). + +Insert 18333fig0410.png +Figure 4-10. GitHub administration page. + +To give another user write access to your project, click the “Add another collaborator” link. A new text box appears, into which you can type a username. As you type, a helper pops up, showing you possible username matches. When you find the correct user, click the Add button to add that user as a collaborator on your project (see Figure 4-11). + +Insert 18333fig0411.png +Figure 4-11. Adding a collaborator to your project. + +When you’re finished adding collaborators, you should see a list of them in the Repository Collaborators box (see Figure 4-12). + +Insert 18333fig0412.png +Figure 4-12. A list of collaborators on your project. + +If you need to revoke access to individuals, you can click the "revoke" link, and their push access will be removed. For future projects, you can also copy collaborator groups by copying the permissions of an existing project. + +### Your Project ### + +After you push your project up or have it imported from Subversion, you have a main project page that looks something like Figure 4-13. + +Insert 18333fig0413.png +Figure 4-13. A GitHub main project page. + +When people visit your project, they see this page. It contains tabs to different aspects of your projects. The Commits tab shows a list of commits in reverse chronological order, similar to the output of the `git log` command. The Network tab shows all the people who have forked your project and contributed back. The Downloads tab allows you to upload project binaries and link to tarballs and zipped versions of any tagged points in your project. The Wiki tab provides a wiki where you can write documentation or other information about your project. The Graphs tab has some contribution visualizations and statistics about your project. The main Source tab that you land on shows your project’s main directory listing and automatically renders the README file below it if you have one. This tab also shows a box with the latest commit information. + +### Forking Projects ### + +If you want to contribute to an existing project to which you don’t have push access, GitHub encourages forking the project. When you land on a project page that looks interesting and you want to hack on it a bit, you can click the "fork" button in the project header to have GitHub copy that project to your user so you can push to it. + +This way, projects don’t have to worry about adding users as collaborators to give them push access. People can fork a project and push to it, and the main project maintainer can pull in those changes by adding them as remotes and merging in their work. + +To fork a project, visit the project page (in this case, mojombo/chronic) and click the "fork" button in the header (see Figure 4-14). + +Insert 18333fig0414.png +Figure 4-14. Get a writable copy of any repository by clicking the "fork" button. + +After a few seconds, you’re taken to your new project page, which indicates that this project is a fork of another one (see Figure 4-15). + +Insert 18333fig0415.png +Figure 4-15. Your fork of a project. + +### GitHub Summary ### + +That’s all we’ll cover about GitHub, but it’s important to note how quickly you can do all this. You can create an account, add a new project, and push to it in a matter of minutes. If your project is open source, you also get a huge community of developers who now have visibility into your project and may well fork it and help contribute to it. At the very least, this may be a way to get up and running with Git and try it out quickly. + +## Summary ## + +You have several options to get a remote Git repository up and running so that you can collaborate with others or share your work. + +Running your own server gives you a lot of control and allows you to run the server within your own firewall, but such a server generally requires a fair amount of your time to set up and maintain. If you place your data on a hosted server, it’s easy to set up and maintain; however, you have to be able to keep your code on someone else’s servers, and some organizations don’t allow that. + +It should be fairly straightforward to determine which solution or combination of solutions is appropriate for you and your organization. diff --git a/fa/NOTES.en-fa.md b/fa/NOTES.en-fa.md new file mode 100644 index 000000000..aef4537e1 --- /dev/null +++ b/fa/NOTES.en-fa.md @@ -0,0 +1,143 @@ +نکاتی در رابطه با ترجمه کتاب +====================== + +همان‌طور که اطلاع دارید کلمات تخصصی اکثر رشته‌ها در زبان فارسی مورد کم لطفی واقع شده‌اند و معمولاً معادل فارسی آن‌ها به صورت رسمی و مدون تعیین نشده‌اند. باالاجبار مترجمان جهت ترجمه این لغات به رای و نظر شخصی خود رجوع می‌کنند. بدین دلیل است که ممکن است برای یک عبارت تخصصی معادل‌های گوناگونی در کتب مختلف یافت شود. + +از آن جهت که ترجمه این کتاب به صورت گروهی انجام می‌پذیرد، برای جلوگیری از سردرگمی خواننده بعد از ترجمه کامل اثر سعی شده است تا لغت‌نامه کوچکی از کلمات کلیدی که در این کتاب به‌کار رفته شده است تهیه شود تا تمامی افرادی که در این کار گروهی شرکت می‌کنند از یک الگوی یکسان در ترجمه پیروی کنند. + +لذا از تمامی افرادی که در ترجمه این کتاب شرکت می‌کنند خواهشمندیم تا از این الگو پیروی کنند و همچنین اگر خود به کلمه کلیدی جدیدی برخورد کردند که در این لیست وجود ندارد، آن را به لیست اضافه کرده و حتی اگر جایگزین مناسبتری برای کلمه خاصی در نظر داشتند با هماهنگی دیگر مترجمان آن را جایگزین کنند. + +توجه: کلماتی که جایگزین مناسبی هنوز برای آن‌ها یافت نشده است، در قسمت معادل فارسی،همان عبارت انگلیسی کلمه آورده شده است. + + +archive +------- + + بایگانی + +branch +------ + + انشعاب + +checkout +-------- + + checkout + +checksum +-------- + + checksum + +clone +----- + + clone + + +commit +------ + + commit + +customize +--------- + + شخصی‌سازی + +diff +---- + + diff + +link +---- + + پیوند + +manpage +------- + + صفحه راهنما + +merge +----- + + merge + +metadata +-------- + + metadata + +option +------ + + گزینه + +package +------- + + بسته + + +patch +----- + +وصله + +platform +-------- + + platform + +push +---- + + push + +remote repository +----------------- + + مخزن خارجی + +repository +---------- + + مخزن + +revision +-------- + + نسخه + +snapshot +-------- + + تصویر لحظه‌ای + +staging area +------------ + + staging area + +state +----- + +وضعیت + +version +------- + +نسخه + +workflow +-------- + +جریان کاری + +working directory +----------------- + +پوشه در حال کار \ No newline at end of file diff --git a/fa/README.md b/fa/README.md new file mode 100644 index 000000000..95dab6b2c --- /dev/null +++ b/fa/README.md @@ -0,0 +1,7 @@ +# تلاش برای ترجمه فارسی # + +## لیست افراد حاضر در این پروژه ## +Oxtay +mxamin + +اگر شما هم برروی این ترجمه کار می‌کنید یا در نظر دارید که این کار را شروع کنید لطفآ به ما اطلاع دهید تا از دوباره کاری پرهیز شود. \ No newline at end of file diff --git a/fi/01-introduction/01-chapter1.markdown b/fi/01-introduction/01-chapter1.markdown index 8ca8f2b98..2c562dca0 100644 --- a/fi/01-introduction/01-chapter1.markdown +++ b/fi/01-introduction/01-chapter1.markdown @@ -97,26 +97,26 @@ Tämä tekee Gitin käyttämisestä hauskaa, koska me tiedämme, että voimme ko ### Kolme tilaa ### -Lue nyt huolellisesti. Tämä on pääasia muistaa Gitistä, jos sinä haluat lopun opiskeluprosessistasi menevän sulavasti. Gitillä on kolme pääasiallista tilaa, joissa tiedostosi voivat olla: pysyvästi muutettu (commited), muutettu (modified), ja lavastettu (staged). Pysyvästi muutettu tarkoittaa, että data on turvallisesti varastoitu sinun paikalliseen tietokantaasi. Muutettu tarkoittaa, että olet muuttanut tiedostoa, mutta et ole tehnyt vielä pysyvää muutosta tietokantaasi. Lavastettu tarkoittaa, että olet merkannut muutetun tiedoston nykyisessä versiossaan menemään seuraavaan pysyvään tilannekuvaan. +Lue nyt huolellisesti. Tämä on pääasia muistaa Gitistä, jos sinä haluat lopun opiskeluprosessistasi menevän sulavasti. Gitillä on kolme pääasiallista tilaa, joissa tiedostosi voivat olla: pysyvästi muutettu (commited), muutettu (modified), ja valmisteltu (staged). Pysyvästi muutettu tarkoittaa, että data on turvallisesti varastoitu sinun paikalliseen tietokantaasi. Muutettu tarkoittaa, että olet muuttanut tiedostoa, mutta et ole tehnyt vielä pysyvää muutosta tietokantaasi. Valmisteltu tarkoittaa, että olet merkannut muutetun tiedoston nykyisessä versiossaan menemään seuraavaan pysyvään tilannekuvaan. -Tämä johdattaa meidät kolmeen seuraavaan osaan Git-projektia: Git-hakemisto, työskentelyhakemisto, ja lavastusalue. +Tämä johdattaa meidät kolmeen seuraavaan osaan Git-projektia: Git-hakemisto, työskentelyhakemisto, ja valmistelualue. Insert 18333fig0106.png -Kuva 1-6. Työskentelyhakemisto, lavastusalue, ja Git-hakemisto. +Kuva 1-6. Työskentelyhakemisto, valmistelualue, ja Git-hakemisto. Git-hakemisto on paikka, johon Git varastoi metadatan ja oliotietokannan projektillesi. Tämä on kaikkein tärkein osa Gitiä, ja se sisältää sen, mitä kopioidaan, kun kloonaat tietovaraston toiselta tietokoneelta. Työskentelyhakemisto on yksittäinen tiedonhaku yhdestä projektin versiosta. Nämä tiedostot vedetään ulos pakatusta tietokannasta Git-hakemistosta ja sijoitetaan levylle sinun käytettäväksesi tai muokattavaksesi. -Lavastusalue on yksinkertainen tiedosto, yleensä se sisältyy Git-hakemistoosi, joka varastoi informaatiota siitä, mitä menee seuraavaan pysyvään muutokseen. Sitä viitataan joskus indeksiksi, mutta on tulossa standardiksi viitata sitä lavastusalueeksi. +Valmistelualue on yksinkertainen tiedosto, yleensä se sisältyy Git-hakemistoosi, joka varastoi informaatiota siitä, mitä menee seuraavaan pysyvään muutokseen. Sitä viitataan joskus indeksiksi, mutta on tulossa standardiksi viitata sitä valmistelualueeksi. Normaali Git-työnkulku menee jokseenkin näin: 1. Muokkaat tiedostoja työskentelyhakemistossasi. -2. Lavastat tiedostosi, lisäten niistä tilannekuvia lavastusalueellesi. -3. Teet pysyvän muutoksen, joka ottaa tiedostot sellaisina, kuin ne ovat lavastusalueella, ja varastoi tämän tilannekuvan pysyvästi sinun Git-tietolähteeseesi. +2. Valmistelet tiedostosi, lisäten niistä tilannekuvia valmistelualueellesi. +3. Teet pysyvän muutoksen, joka ottaa tiedostot sellaisina, kuin ne ovat valmistelualueella, ja varastoi tämän tilannekuvan pysyvästi sinun Git-tietolähteeseesi. -Jos tietty versio tiedostosta on Git-hakemistossa, se on yhtä kuin pysyvä muutos. Jos sitä on muokattu, mutta se on lisätty lavastusalueelle, se on lavastettu. Ja jos se on muuttunut siitä, kun se on haettu, mutta sitä ei ole lavastettu, se on muutettu. Luvussa 2 opit enemmän näistä tiloista ja kuinka voit hyödyntää niitä tai ohittaa lavastusosan kokonaan. +Jos tietty versio tiedostosta on Git-hakemistossa, se on yhtä kuin pysyvä muutos. Jos sitä on muokattu, mutta se on lisätty valmistelualueelle, se on valmisteltu. Ja jos se on muuttunut siitä, kun se on haettu, mutta sitä ei ole valmisteltu, se on muutettu. Luvussa 2 opit enemmän näistä tiloista ja kuinka voit hyödyntää niitä tai ohittaa valmisteluvaiheen kokonaan. ## Gitin asennus ## @@ -163,7 +163,7 @@ Tai jos olet Debian-pohjaisessa julkaisussa kuten Ubuntussa, kokeile apt-getiä: On olemassa kaksi helppoa tapaa asentaa Git Macissä. Helpoin on käyttää graafista Git-asennusohjelmaa, jonka voit ladata Googlen Code -verkkosivuilta (katso Kuva 1-7): - http://code.google.com/p/git-osx-installer + http://sourceforge.net/projects/git-osx-installer/ Insert 18333fig0107.png Kuva 1-7. Git OS X -asennusohjelma. diff --git a/fi/02-git-basics/01-chapter2.markdown b/fi/02-git-basics/01-chapter2.markdown index f5c7f1ab0..259e0b2cb 100644 --- a/fi/02-git-basics/01-chapter2.markdown +++ b/fi/02-git-basics/01-chapter2.markdown @@ -1,6 +1,6 @@ # Gitin perusteet # -Jos voit lukea vain yhden kappaleen päästäksesi vauhtiin Gitin kanssa, se on tämä kappale. Tämä kappale sisältää jokaisen peruskomennon, jonka tarvitset tehdäksesi valtavan määrän asioita, joiden kanssa viimein tulet käyttämään aikaasi Gitillä työskennellessäsi. Tämän kappaleen lopussa, sinun tulisi pystyä konfiguroimaan ja alustamaan tietolähde, aloittamaan ja lopettamaan tiedostojen jäljitys sekä lavastaa ja tehdä pysyviä muutoksia. Me myös näytämme sinulle kuinka asettaa Git niin, että se jättää tietyt tiedostot ja tiedostomallit huomioimatta, kuinka kumota virheet nopeasti ja helposti, kuinka selata projektisi historiaa ja tarkastella muutoksia pysyvien muutosten välillä sekä kuinka työntää ja vetää etätietolähteistä. +Jos voit lukea vain yhden kappaleen päästäksesi vauhtiin Gitin kanssa, se on tämä kappale. Tämä kappale sisältää jokaisen peruskomennon, jonka tarvitset tehdäksesi valtavan määrän asioita, joiden kanssa viimein tulet käyttämään aikaasi Gitillä työskennellessäsi. Tämän kappaleen lopussa, sinun tulisi pystyä konfiguroimaan ja alustamaan tietolähde, aloittamaan ja lopettamaan tiedostojen jäljitys sekä valmistelemaan ja tehdä pysyviä muutoksia. Me myös näytämme sinulle kuinka asettaa Git niin, että se jättää tietyt tiedostot ja tiedostomallit huomioimatta, kuinka kumota virheet nopeasti ja helposti, kuinka selata projektisi historiaa ja tarkastella muutoksia pysyvien muutosten välillä sekä kuinka työntää ja vetää etätietolähteistä. ## Git-tietolähteen hankinta ## @@ -42,9 +42,9 @@ Gitissä on monta erilaista siirtoprotokollaa, joita voit käyttää. Edellinen Sinulla on oikea Git-tietolähde ja tiedonhaku (checkout) tai työkopio projektin tiedostoista. Sinun täytyy tehdä joitain muutoksia ja pysyviä tilannekuvia näistä muutoksista sinun tietolähteeseesi joka kerta, kun projekti saavuttaa tilan, jonka haluat tallentaa. -Muista, että jokainen tiedosto työhakemistossasi voi olla yhdessä kahdesta tilasta: *jäljitetty* tai *jäljittämätön*. *Jäljitetyt* tiedostot ovat tiedostoja, jotka olivat viimeisimmässä tilannekuvassa; ne voivat olla *muokkaamattomia*, *muokattuja* tai *lavastettuja*. *Jäljittämättömät* tiedostot ovat kaikkea muuta - mitkä tahansa tiedostoja työhakemistossasi, jotka eivät olleet viimeisimmässä tilannekuvassa ja jotka eivät ole lavastusalueella. Kun ensimmäisen kerran kloonaat tietolähteen, kaikki tiedostoistasi tulevat olemaan jäljitettyjä ja muokkaamattomia, koska sinä juuri hait ne etkä ole muokannut vielä mitään. +Muista, että jokainen tiedosto työhakemistossasi voi olla yhdessä kahdesta tilasta: *jäljitetty* tai *jäljittämätön*. *Jäljitetyt* tiedostot ovat tiedostoja, jotka olivat viimeisimmässä tilannekuvassa; ne voivat olla *muokkaamattomia*, *muokattuja* tai *valmisteltuja*. *Jäljittämättömät* tiedostot ovat kaikkea muuta - mitkä tahansa tiedostoja työhakemistossasi, jotka eivät olleet viimeisimmässä tilannekuvassa ja jotka eivät ole valmistelualueella. Kun ensimmäisen kerran kloonaat tietolähteen, kaikki tiedostoistasi tulevat olemaan jäljitettyjä ja muokkaamattomia, koska sinä juuri hait ne etkä ole muokannut vielä mitään. -Editoidessasi tiedostoja Git näkee ne muokattuina, koska olet muuttanut niitä viimeisimmän pysyvän muutoksen jälkeen. *Lavastat* nämä muutetut tiedostot, jonka jälkeen muutat kaikki lavastetut muutokset pysyvästi, ja sykli toistuu. Tämä elämänsykli on kuvattu Kuvassa 2-1. +Editoidessasi tiedostoja Git näkee ne muokattuina, koska olet muuttanut niitä viimeisimmän pysyvän muutoksen jälkeen. *Valmistelet* nämä muutetut tiedostot, jonka jälkeen muutat kaikki valmistellut muutokset pysyvästi, ja sykli toistuu. Tämä elämänsykli on kuvattu Kuvassa 2-1. Insert 18333fig0201.png Kuva 2-1. Tiedostojesi tilan elämänsykli. @@ -55,7 +55,7 @@ Päätyökalu tiedostojesi eri tilojen selvittämiseen on `git status` -komento. $ git status # On branch master - nothing to commit (working directory clean) + nothing to commit, working directory clean Tämä tarkoittaa, että sinulla on puhdas työhakemisto - toisin sanoen, jäljitettyjä tiedostoja ei ole muutettu. Git ei myöskään näe yhtään jäljittämätöntä tiedostoa, muuten ne olisi listattu näkymään. Lopuksi komento kertoo sinulle missä haarassa olet. Tällä hetkellä se on aina `master`-haara, joka on oletusarvo; sinun ei tarvitse huolehtia siitä nyt. Seuraava luku käy läpi haarautumiset ja viittaukset yksityiskohtaisesti. @@ -78,7 +78,7 @@ Jotta voisit jäljittää uusia tiedostoja, sinun täytyy käyttää `git add` - $ git add README -Jos ajat status-komennon uudestaan, näet että `README`-tiedostosi on nyt jäljitetty ja lavastettu: +Jos ajat status-komennon uudestaan, näet että `README`-tiedostosi on nyt jäljitetty ja valmisteltu: $ git status # On branch master @@ -88,9 +88,9 @@ Jos ajat status-komennon uudestaan, näet että `README`-tiedostosi on nyt jälj # new file: README # -Voit nähdä, että se on lavastettu, koska se on otsikon ”Changes to be committed” alla. Jos teet pysyvän muutoksen tässä kohtaa, versio tiedostosta sillä hetkellä kun ajoit `git add` -komennon on se, joka tulee olemaan historian tilannekuvassa. Voit palauttaa mieleen hetken, jolloin ajoit `git init` -komennon aikaisemmin, ajoit sen jälkeen `git add (tiedostot)` -komennon - tämä komento aloitti tiedostojen jäljittämisen hakemistossa. `Git add` -komento ottaa polun nimen joko tiedostolle tai hakemistolle; jos se on hakemisto, komento lisää kaikki tiedostot hakemiston alta rekursiivisesti. +Voit nähdä, että se on valmisteltu, koska se on otsikon ”Changes to be committed” alla. Jos teet pysyvän muutoksen tässä kohtaa, versio tiedostosta sillä hetkellä kun ajoit `git add` -komennon on se, joka tulee olemaan historian tilannekuvassa. Voit palauttaa mieleen hetken, jolloin ajoit `git init` -komennon aikaisemmin, ajoit sen jälkeen `git add (tiedostot)` -komennon - tämä komento aloitti tiedostojen jäljittämisen hakemistossa. `Git add` -komento ottaa polun nimen joko tiedostolle tai hakemistolle; jos se on hakemisto, komento lisää kaikki tiedostot hakemiston alta rekursiivisesti. -### Muutettujen tiedostojen lavastus ### +### Muutettujen tiedostojen valmistelu ### Muutetaanpa tiedostoa, joka on jo jäljitetty. Jos muutat aikaisemmin jäljitettyä `benchmarks.rb`-tiedostoa ja sen jälkeen ajat `status`-komennon uudestaan, saat suunnilleen tämän näköisen tulosteen: @@ -107,7 +107,7 @@ Muutetaanpa tiedostoa, joka on jo jäljitetty. Jos muutat aikaisemmin jäljitett # modified: benchmarks.rb # -`Benchmarks.rb`-tiedosto näkyy kohdan ”Changes not staged for commit” alla - mikä tarkoittaa, että tiedostoa, jota jäljitetään, on muokattu työskentelyhakemistossa, mutta sitä ei vielä ole lavastettu. Lavastaaksesi sen, ajat `git add` -komennon (se on monitoimikomento - käytät sitä aloittaaksesi uusien tiedostojen jäljittämisen, lavastaaksesi tiedostoja, ja tehdäksesi muita asioita, kuten merkataksesi liitoskonfliktitiedostot ratkaistuksi). Ajetaanpa nyt `git add` -komento lavastaaksemme `benchmarks.rb`-tiedoston, ja ajetaan sitten `git status` -komento uudestaan: +`Benchmarks.rb`-tiedosto näkyy kohdan ”Changes not staged for commit” alla - mikä tarkoittaa, että tiedostoa, jota jäljitetään, on muokattu työskentelyhakemistossa, mutta sitä ei vielä ole valmisteltu. Valmistellaksesi sen, ajat `git add` -komennon (se on monitoimikomento - käytät sitä aloittaaksesi uusien tiedostojen jäljittämisen, valmistellaksesi tiedostoja, ja tehdäksesi muita asioita, kuten merkataksesi liitoskonfliktitiedostot ratkaistuksi). Ajetaanpa nyt `git add` -komento valmistellaksemme `benchmarks.rb`-tiedoston, ja ajetaan sitten `git status` -komento uudestaan: $ git add benchmarks.rb $ git status @@ -119,7 +119,7 @@ Muutetaanpa tiedostoa, joka on jo jäljitetty. Jos muutat aikaisemmin jäljitett # modified: benchmarks.rb # -Kummatkin tiedostot ovat lavastettuja ja tulevat menemään seuraavaan pysyvään muutokseen. Oletetaan, että tässä kohdassa muistat pienen muutoksen, jonka haluat tehdä `benchmarks.rb`-tiedostoon, ennen kuin teet pysyvää muutosta. Avaat tiedoston uudestaan ja muutat sitä, jonka jälkeen olet valmis tekemään pysyvän muutoksen. Ajetaan silti `git status` -komento vielä kerran: +Kummatkin tiedostot ovat valmisteltuja ja tulevat menemään seuraavaan pysyvään muutokseen. Oletetaan, että tässä kohdassa muistat pienen muutoksen, jonka haluat tehdä `benchmarks.rb`-tiedostoon, ennen kuin teet pysyvää muutosta. Avaat tiedoston uudestaan ja muutat sitä, jonka jälkeen olet valmis tekemään pysyvän muutoksen. Ajetaan silti `git status` -komento vielä kerran: $ vim benchmarks.rb $ git status @@ -136,7 +136,7 @@ Kummatkin tiedostot ovat lavastettuja ja tulevat menemään seuraavaan pysyvää # modified: benchmarks.rb # -Mitä ihmettä? Nyt `benchmarks.rb` on listattu sekä lavastettuna että lavastamattomana. Miten se on mahdollista? Tapahtuu niin, että Git lavastaa tiedoston juuri sellaisena kuin se on, kun ajat `git add` -komennon. Jos teet pysyvän muutoksen nyt, `benchmark.rb`-tiedoston versio sillä hetkellä, kun ajoit `git add` -komennon, on se, joka menee tähän pysyvään muutokseen, eikä se tiedoston versio, joka on työskentelyhakemistossasi sillä hetkellä, kun ajat `git commit` -komennon. Jos muutat tiedostoa sen jälkeen, kun olet ajanut `git add` -komennon, sinun täytyy ajaa `git add` uudestaan lavastaaksesi uusimman version tiedostosta: +Mitä ihmettä? Nyt `benchmarks.rb` on listattu sekä valmisteltuna että valmistelemattomana. Miten se on mahdollista? Tapahtuu niin, että Git valmistelee tiedoston juuri sellaisena kuin se on, kun ajat `git add` -komennon. Jos teet pysyvän muutoksen nyt, `benchmark.rb`-tiedoston versio sillä hetkellä, kun ajoit `git add` -komennon, on se, joka menee tähän pysyvään muutokseen, eikä se tiedoston versio, joka on työskentelyhakemistossasi sillä hetkellä, kun ajat `git commit` -komennon. Jos muutat tiedostoa sen jälkeen, kun olet ajanut `git add` -komennon, sinun täytyy ajaa `git add` uudestaan valmistellaksesi uusimman version tiedostosta: $ git add benchmarks.rb $ git status @@ -185,11 +185,11 @@ Tässä toinen esimerkki .gitignore-tiedostosta: `**/`-malli on saatavilla Gitin versiosta 1.8.2 lähtien. -### Lavastettujen ja lavastamattomien muutosten tarkastelu ### +### Valmisteltujen ja valmistelemattomien muutosten tarkastelu ### -Jos `git status` -komento on liian epämääräinen sinulle - haluat tietää tarkalleen mitä on muutettu, et ainoastaan sitä, mitkä tiedostot ovat muuttuneet - voit käyttää `git diff` -komentoa. Me käsittelemme `git diff` -kommenon yksityiskohtaisesti myöhemmin; mutta sinä tulet mahdollisesti käyttämään sitä useasti, vastataksesi näihin kahteen kysymykseen: Mitä olet muuttanut, mutta et ole vielä lavastanut? Ja mitä sellaista olet lavastanut, josta olet tekemässä pysyvän muutoksen? Vaikkakin `git status` vastaa näihin kysymyksiin yleisesti, `git diff` näyttää sinulle tarkalleen ne rivit, jotka on lisätty ja poistettu - vähän niin kuin pätsi. +Jos `git status` -komento on liian epämääräinen sinulle - haluat tietää tarkalleen mitä on muutettu, et ainoastaan sitä, mitkä tiedostot ovat muuttuneet - voit käyttää `git diff` -komentoa. Me käsittelemme `git diff` -kommenon yksityiskohtaisesti myöhemmin; mutta sinä tulet mahdollisesti käyttämään sitä useasti, vastataksesi näihin kahteen kysymykseen: Mitä olet muuttanut, mutta et ole vielä valmistellut? Ja mitä sellaista olet valmistellut, josta olet tekemässä pysyvän muutoksen? Vaikkakin `git status` vastaa näihin kysymyksiin yleisesti, `git diff` näyttää sinulle tarkalleen ne rivit, jotka on lisätty ja poistettu - vähän niin kuin pätsi. -Sanotaan vaikka, että muokkaat ja lavastat `README`-tiedostoa uudestaan, jonka jälkeen muokkaat `benchmarks.rb`-tiedostoa, ilman että lavastat sitä. Jos ajat `status`-komennon, näet jälleen kerran jotain tällaista: +Sanotaan vaikka, että muokkaat ja valmistelet `README`-tiedostoa uudestaan, jonka jälkeen muokkaat `benchmarks.rb`-tiedostoa, ilman että valmistelet sitä. Jos ajat `status`-komennon, näet jälleen kerran jotain tällaista: $ git status # On branch master @@ -204,7 +204,7 @@ Sanotaan vaikka, että muokkaat ja lavastat `README`-tiedostoa uudestaan, jonka # modified: benchmarks.rb # -Nähdäksesi, mitä olet muuttanut, mutta et vielä lavastanut, kirjoita `git diff` ilman mitään muita argumentteja: +Nähdäksesi, mitä olet muuttanut, mutta et vielä valmistellut, kirjoita `git diff` ilman mitään muita argumentteja: $ git diff diff --git a/benchmarks.rb b/benchmarks.rb @@ -223,9 +223,9 @@ Nähdäksesi, mitä olet muuttanut, mutta et vielä lavastanut, kirjoita `git di log = git.commits('master', 15) log.size -Tämä komento vertailee sitä, mitä sinun työskentelyhakemistossa on verrattuna siihen, mitä sinun lavastusalueellasi on. Tulos kertoo tekemäsi muutokset, joita et ole vielä lavastanut. +Tämä komento vertailee sitä, mitä sinun työskentelyhakemistossa on verrattuna siihen, mitä sinun valmistelualueellasi on. Tulos kertoo tekemäsi muutokset, joita et ole vielä valmistellut. -Jos haluat nähdä, mitä sellaista olet lavastanut, joka menee seuraavaan pysyvään muutokseen, voit käyttää `git diff --cached` -komentoa. (Gitin versiosta 1.6.1 lähtien voit käyttää myös `git diff --staged` -komentoa, joka on helpompi muistaa.) Tämä komento vertailee lavastettuja muutoksia viimeisimpään pysyvään muutokseen. +Jos haluat nähdä, mitä sellaista olet valmistellut, joka menee seuraavaan pysyvään muutokseen, voit käyttää `git diff --cached` -komentoa. (Gitin versiosta 1.6.1 lähtien voit käyttää myös `git diff --staged` -komentoa, joka on helpompi muistaa.) Tämä komento vertailee valmisteltuja muutoksia viimeisimpään pysyvään muutokseen. $ git diff --cached diff --git a/README b/README @@ -240,9 +240,9 @@ Jos haluat nähdä, mitä sellaista olet lavastanut, joka menee seuraavaan pysyv + +Grit is a Ruby library for extracting information from a Git repository -On tärkeää ottaa huomioon, että `git diff` itsessään ei näytä kaikkia muutoksia viimeisimmästä pysyvästä muutoksesta lähtien - vain muutokset, jotka ovat yhä lavastamattomia. Tämä voi olla sekavaa, koska kun olet lavastanut kaikki muutoksesi, `git diff` ei anna ollenkaan tulostetta. +On tärkeää ottaa huomioon, että `git diff` itsessään ei näytä kaikkia muutoksia viimeisimmästä pysyvästä muutoksesta lähtien - vain muutokset, jotka ovat yhä valmistelemattomia. Tämä voi olla sekavaa, koska kun olet valmistellut kaikki muutoksesi, `git diff` ei anna ollenkaan tulostetta. -Toisena esimerkkinä, jos lavastat `benchmarks.rb`-tiedoston ja sitten muokkaat sitä, voit käyttää `git diff` -komentoa nähdäksesi tiedoston lavastetut muutokset ja lavastamattomat muutokset: +Toisena esimerkkinä, jos valmistelet `benchmarks.rb`-tiedoston ja sitten muokkaat sitä, voit käyttää `git diff` -komentoa nähdäksesi tiedoston valmistellut muutokset ja valmistelemattomat muutokset: $ git add benchmarks.rb $ echo '# test line' >> benchmarks.rb @@ -258,7 +258,7 @@ Toisena esimerkkinä, jos lavastat `benchmarks.rb`-tiedoston ja sitten muokkaat # modified: benchmarks.rb # -Nyt voit käyttää `git diff` -komentoa nähdäksesi, mitä on yhä lavastamatta: +Nyt voit käyttää `git diff` -komentoa nähdäksesi, mitä on yhä valmistelematta: $ git diff diff --git a/benchmarks.rb b/benchmarks.rb @@ -271,7 +271,7 @@ Nyt voit käyttää `git diff` -komentoa nähdäksesi, mitä on yhä lavastamatt ##pp Grit::GitRuby.cache_client.stats +# test line -Ja `git diff --cached` -komentoa nähdäksesi, mitä olet lavastanut tähän mennessä: +Ja `git diff --cached` -komentoa nähdäksesi, mitä olet valmistellut tähän mennessä: $ git diff --cached diff --git a/benchmarks.rb b/benchmarks.rb @@ -292,8 +292,8 @@ Ja `git diff --cached` -komentoa nähdäksesi, mitä olet lavastanut tähän men ### Pysyvien muutoksien tekeminen ### -Nyt, kun lavastusalueesi on asetettu niin kuin sen haluat, voit tehdä muutoksistasi pysyviä. Muista, että kaikki, mikä vielä on lavastamatta - mitkä tahansa tiedostot, jotka olet luonut tai joita olet muokannut, joihin et ole ajanut `git add` -komentoa editoinnin jälkeen - eivät mene pysyvään muutokseen. Ne pysyvät muokattuina tiedostoina levylläsi. -Tässä tapauksessa oletamme, että viime kerran, kun ajoit `git status` -komennon, näit, että kaikki oli lavastettu, joten olet valmis tekemään pysyvän muutoksen. Helpoin tapa pysyvän muutoksen tekoon on kirjoittaa `git commit`: +Nyt, kun valmistelualueesi on asetettu niin kuin sen haluat, voit tehdä muutoksistasi pysyviä. Muista, että kaikki, mikä vielä on valmistelematta - mitkä tahansa tiedostot, jotka olet luonut tai joita olet muokannut, joihin et ole ajanut `git add` -komentoa editoinnin jälkeen - eivät mene pysyvään muutokseen. Ne pysyvät muokattuina tiedostoina levylläsi. +Tässä tapauksessa oletamme, että viime kerran, kun ajoit `git status` -komennon, näit, että kaikki oli valmisteltu, joten olet valmis tekemään pysyvän muutoksen. Helpoin tapa pysyvän muutoksen tekoon on kirjoittaa `git commit`: $ git commit @@ -325,11 +325,11 @@ Vaihtoehtoisesti, voit kirjoittaa pysyvän muutoksen viestin suoraan `commit`-ko Nyt olet luonut ensimmäisen pysyvän muutoksen! Voit nähdä, että pysyvä muutos on antanut sinulle tulosteen itsestään: kertoen mihin haaraan teit pysyvän muutoksen (`master`), mikä SHA-1 tarkistussumma pysyvällä muutoksella on (`463dc4f`), kuinka monta tiedostoa muutettiin ja tilastoja pysyvän muutoksen rivien lisäyksistä ja poistoista. -Muista, että pysyvä muutos tallentaa tilannekuvan lavastusalueestasi. Kaikki, mitä et lavastanut on yhä istumassa projektissasi muokattuna; voit tehdä toisen pysyvän muutoksen lisätäksesi ne historiaasi. Joka kerta, kun teet pysyvän muutoksen, olet tallentamassa tilannekuvaa projektistasi. Tilannekuvaa, johon voit palata tai jota voit vertailla myöhemmin. +Muista, että pysyvä muutos tallentaa tilannekuvan valmistelualueestasi. Kaikki, mitä et valmistellut on yhä istumassa projektissasi muokattuna; voit tehdä toisen pysyvän muutoksen lisätäksesi ne historiaasi. Joka kerta, kun teet pysyvän muutoksen, olet tallentamassa tilannekuvaa projektistasi. Tilannekuvaa, johon voit palata tai jota voit vertailla myöhemmin. -### Lavastusalueen ohittaminen ### +### Valmistelualueen ohittaminen ### -Vaikka lavastusalue voi olla uskomattoman hyödyllinen pysyvien muutoksien tekoon tarkalleen niin kuin ne haluat, on lavastusalue joskus hieman liian monimutkainen, kuin mitä työnkulussasi tarvitsisit. Jos haluat ohittaa lavastusalueen, Git tarjoaa siihen helpon oikoreitin. Antamalla `-a`-option `git commit` -komennolle, asettaa Gitin automaattisesti lavastamaan jokaisen jo jäljitetyn tiedoston ennen pysyvää muutosta, antaen sinun ohittaa `git add` -osan: +Vaikka valmistelualue voi olla uskomattoman hyödyllinen pysyvien muutoksien tekoon tarkalleen niin kuin ne haluat, on valmistelualue joskus hieman liian monimutkainen, kuin mitä työnkulussasi tarvitsisit. Jos haluat ohittaa valmistelualueen, Git tarjoaa siihen helpon oikoreitin. Antamalla `-a`-option `git commit` -komennolle, asettaa Gitin automaattisesti valmistelemaan jokaisen jo jäljitetyn tiedoston ennen pysyvää muutosta, antaen sinun ohittaa `git add` -osan: $ git status # On branch master @@ -346,9 +346,9 @@ Huomaa, miten sinun ei tarvitse ajaa `git add` -komentoa `benchmarks.rb`-tiedost ### Tiedostojen poistaminen ### -Poistaaksesi tiedoston Gitistä, sinun täytyy poistaa se sinun jäljitetyistä tiedostoistasi (tarkemmin sanoen, poistaa se lavastusalueeltasi) ja sitten tehdä pysyvä muutos. Komento `git rm` tekee tämän ja myös poistaa tiedoston työskentelyhakemistostasi, joten et näe sitä enää jäljittämättömänä tiedostona. +Poistaaksesi tiedoston Gitistä, sinun täytyy poistaa se sinun jäljitetyistä tiedostoistasi (tarkemmin sanoen, poistaa se valmistelualueeltasi) ja sitten tehdä pysyvä muutos. Komento `git rm` tekee tämän ja myös poistaa tiedoston työskentelyhakemistostasi, joten et näe sitä enää jäljittämättömänä tiedostona. -Jos yksinkertaisesti poistat tiedoston työskentelyhakemistostasi, näkyy se ”Changes not staged for commit” otsikon alla (se on, _lavastamaton_) `git status` -tulosteessasi: +Jos yksinkertaisesti poistat tiedoston työskentelyhakemistostasi, näkyy se ”Changes not staged for commit” otsikon alla (se on, _valmistelematon_) `git status` -tulosteessasi: $ rm grit.gemspec $ git status @@ -360,7 +360,7 @@ Jos yksinkertaisesti poistat tiedoston työskentelyhakemistostasi, näkyy se ” # deleted: grit.gemspec # -Jos ajat tämän jälkeen `git rm` -komennon, se lavastaa tiedostot poistoon: +Jos ajat tämän jälkeen `git rm` -komennon, se valmistelee tiedostot poistoon: $ git rm grit.gemspec rm 'grit.gemspec' @@ -375,7 +375,7 @@ Jos ajat tämän jälkeen `git rm` -komennon, se lavastaa tiedostot poistoon: Seuraavan kerran, kun teet pysyvän muutoksen, tiedosto katoaa ja sitä ei jäljitetä enää. Jos muokkasit tiedostoa ja lisäsit sen jo indeksiin, täytyy sinun pakottaa poisto `-f`-optiolla. Tämä on turvallisuusominaisuus, joka estää vahingossa tapahtuvan datan poistamisen, datan, jota ei ole vielä tallennettu tilannekuvaksi ja jota ei voida palauttaa Gitistä. -Toinen hyödyllinen asia, jonka saatat haluta tehdä, on tiedoston pitäminen työskentelypuussa, mutta samalla sen poistaminen lavastusalueelta. Toisin sanoen, voit haluta pitää tiedoston kovalevylläsi, mutta et halua, että Git jäljittää sitä enää. Tämä on erityisesti hyödyllinen, jos unohdit lisätä jotain `.gitignore`-tiedostoosi ja vahingossa lavastit sellaisen, kuten suuri lokitiedosto tai joukko `.a`-muotoon käännettyjä tiedostoja. Tehdäksesi tämän, käytä `--cached`-optiota: +Toinen hyödyllinen asia, jonka saatat haluta tehdä, on tiedoston pitäminen työskentelypuussa, mutta samalla sen poistaminen valmistelualueelta. Toisin sanoen, voit haluta pitää tiedoston kovalevylläsi, mutta et halua, että Git jäljittää sitä enää. Tämä on erityisesti hyödyllinen, jos unohdit lisätä jotain `.gitignore`-tiedostoosi ja vahingossa valmistelit sellaisen, kuten suuri lokitiedosto tai joukko `.a`-muotoon käännettyjä tiedostoja. Tehdäksesi tämän, käytä `--cached`-optiota: $ git rm --cached readme.txt @@ -682,11 +682,11 @@ Yksi yleinen kumoaminen tapahtuu, kun teet pysyvän muutoksen liian aikaisin ja $ git commit --amend -Tämä komento ottaa lavastusalueesi ja käyttää sitä pysyvään muutokseen. Jos et ole tehnyt muutoksia viimeisimmän pysyvän muutoksesi jälkeen (esimerkiksi, jos ajat tämän komennon heti edellisen pysyvän muutoksesi jälkeen), tilannekuvasi näyttää tarkalleen samalta ja kaikki, mitä muutat, on pysyvän muutoksesi viesti. +Tämä komento ottaa valmistelualueesi ja käyttää sitä pysyvään muutokseen. Jos et ole tehnyt muutoksia viimeisimmän pysyvän muutoksesi jälkeen (esimerkiksi, jos ajat tämän komennon heti edellisen pysyvän muutoksesi jälkeen), tilannekuvasi näyttää tarkalleen samalta ja kaikki, mitä muutat, on pysyvän muutoksesi viesti. Sama pysyvän muutoksen viestin editori aktivoituu, mutta se sisältää jo viestin edellisestä pysyvästä muutoksesta. Voit muokata viestiä samoin kuin aina, mutta se korvaa edellisen pysyvän muutoksesi. -Esimerkkinä, jos teet pysyvän muutoksen ja sitten huomaat unohtaneesi lavastaa muutokset tiedostossa, jonka haluat lisätä tähän pysyvään muutokseen, voit tehdä jotakuinkin seuraavasti: +Esimerkkinä, jos teet pysyvän muutoksen ja sitten huomaat unohtaneesi valmistelee muutokset tiedostossa, jonka haluat lisätä tähän pysyvään muutokseen, voit tehdä jotakuinkin seuraavasti: $ git commit -m 'initial commit' $ git add unohtunut_tiedosto @@ -694,9 +694,9 @@ Esimerkkinä, jos teet pysyvän muutoksen ja sitten huomaat unohtaneesi lavastaa Näiden kolmen komennon jälkeen päädyt yhteen pysyvään muutokseen — toinen pysyvä muutos korvaa ensimmäisen. -### Lavastetun tiedoston lavastuksen purkaminen ### +### Valmistellun tiedoston valmistelun purkaminen ### -Kaksi seuraavaa kappaletta havainnollistavat, kuinka paimentaa muutoksia lavastusalueellasi ja työskentelyhakemistossasi. Mukava osa on, että komento, jota käytät selvittääksesi näiden kahden alueen tilan, muistuttaa sinua myös, kuinka peruuttaa muutokset niihin. Sanokaamme, esimerkiksi, että olet muuttanut kahta tiedostoa ja haluat tehdä niistä kaksi erillistä pysyvää muutosta, mutta kirjoitit vahingossa `git add *` ja lavastit ne molemmat. Kuinka voit purkaa toisen lavastuksen? `Git status` -komento muistuttaa sinua: +Kaksi seuraavaa kappaletta havainnollistavat, kuinka paimentaa muutoksia valmistelualueellasi ja työskentelyhakemistossasi. Mukava osa on, että komento, jota käytät selvittääksesi näiden kahden alueen tilan, muistuttaa sinua myös, kuinka peruuttaa muutokset niihin. Sanokaamme, esimerkiksi, että olet muuttanut kahta tiedostoa ja haluat tehdä niistä kaksi erillistä pysyvää muutosta, mutta kirjoitit vahingossa `git add *` ja valmistelit ne molemmat. Kuinka voit purkaa toisen valmistelun? `Git status` -komento muistuttaa sinua: $ git add . $ git status @@ -708,7 +708,7 @@ Kaksi seuraavaa kappaletta havainnollistavat, kuinka paimentaa muutoksia lavastu # modified: benchmarks.rb # -Heti ”Changes to be committed” -tekstin alla, sanotaan "use `git reset HEAD ...` to unstage". Joten, käyttäkäämme tätä neuvoa purkaaksemme `benchmarks.rb`-tiedoston lavastuksen: +Heti ”Changes to be committed” -tekstin alla, sanotaan "use `git reset HEAD ...` to unstage". Joten, käyttäkäämme tätä neuvoa purkaaksemme `benchmarks.rb`-tiedoston valmistelun: $ git reset HEAD benchmarks.rb benchmarks.rb: locally modified @@ -726,11 +726,11 @@ Heti ”Changes to be committed” -tekstin alla, sanotaan "use `git reset HEAD # modified: benchmarks.rb # -Komento on hieman kummallinen, mutta se toimii. `Benchmarks.rb`-tiedosto on muokattu mutta lavastamaton jälleen. +Komento on hieman kummallinen, mutta se toimii. `Benchmarks.rb`-tiedosto on muokattu mutta valmistelematon jälleen. ### Muutetun tiedoston muutosten kumoaminen ### -Mitä, jos tajuat, ettet halua säilyttää muutoksiasi `benchmarks.rb`-tiedostoon? Kuinka voit helposti kumota sen muutokset — palauttaa sen takaisin sellaiseksi, miltä se näytti, kun teit viimeksi pysyvän muutoksen (tai alun perin kloonasit tai miten saitkaan sen työskentelyhakemistoosi)? Onneksi `git status` kertoo sinulle myös, miten tämä tehdään. Edellisessä esimerkkitulosteessa lavastamaton alue näyttää tältä: +Mitä, jos tajuat, ettet halua säilyttää muutoksiasi `benchmarks.rb`-tiedostoon? Kuinka voit helposti kumota sen muutokset — palauttaa sen takaisin sellaiseksi, miltä se näytti, kun teit viimeksi pysyvän muutoksen (tai alun perin kloonasit tai miten saitkaan sen työskentelyhakemistoosi)? Onneksi `git status` kertoo sinulle myös, miten tämä tehdään. Edellisessä esimerkkitulosteessa valmistelematon alue näyttää tältä: # Changes not staged for commit: # (use "git add ..." to update what will be committed) diff --git a/fi/NOTES b/fi/NOTES index fef3c2fe5..84cb89f3c 100644 --- a/fi/NOTES +++ b/fi/NOTES @@ -1,4 +1,5 @@ Chapter 1 - Line 56: What is a proper finnish translation for the word "snapshot" in this case? Translated now as 'tilannekuvat'. Multiline: What is a proper finnish translation for the word "commit" in this case? Or do we need it, is permanen change (like it is now) enought to tell what it is about? - Chapter "The Three Stages" ("Kolme tilaa") has mentioned the "staged" word, what is correct translation for this in finnish? Now translated as "lavastettu". + Chapter "The Three Stages" ("Kolme tilaa") has mentioned the "staged" word, what is correct translation for this in finnish? Was translated as "lavastettu". + -> "lavastettu" is an obvious but bad choice, because it's based on another meaning of "stage", not the one that Git uses. Now translated as "valmisteltu". Line 230: Translation for a word "Backports" diff --git a/fr/01-introduction/01-chapter1.markdown b/fr/01-introduction/01-chapter1.markdown index 73cb6bee2..9985aa6f0 100644 --- a/fr/01-introduction/01-chapter1.markdown +++ b/fr/01-introduction/01-chapter1.markdown @@ -118,7 +118,7 @@ Nous explorerons les bénéfices qu'il y a à penser les données de cette mani ### Presque toutes les opérations sont locales ### -La plupart des opérations de Git ne nécessite que des fichiers et ressources locaux — généralement aucune information venant d'un autre ordinateur du réseau n'est nécessaire. +La plupart des opérations de Git ne nécessitent que des fichiers et ressources locaux — généralement aucune information venant d'un autre ordinateur du réseau n'est nécessaire. Si vous êtes habitué à un CVCS où toutes les opérations sont ralenties par la latence des échanges réseau, cet aspect de Git vous fera penser que les dieux de la vitesse ont octroyé leurs pouvoirs à Git. Comme vous disposez de l'historique complet du projet localement sur votre disque dur, la plupart des opérations semblent instantanées. @@ -239,7 +239,7 @@ Après ceci, vous pouvez obtenir Git par Git lui-même pour les mises à jour : Si vous souhaitez installer Git sur Linux via un installateur d'application, vous pouvez généralement le faire via le système de gestion de paquets de base fourni avec votre distribution. Si vous êtes sur Fedora, vous pouvez utiliser yum : - $ yum install git-core + $ yum install git Si vous êtes sur un système basé sur Debian, tel qu'Ubuntu, essayez apt-get : @@ -248,9 +248,9 @@ Si vous êtes sur un système basé sur Debian, tel qu'Ubuntu, essayez apt-get  ### Installation sur Mac ### Il y a deux moyens simples d'installer Git sur Mac. -Le plus simple et d'utiliser l'installateur graphique de Git que vous pouvez télécharger depuis les pages Google Code (voir figure 1-7) : +Le plus simple et d'utiliser l'installateur graphique de Git que vous pouvez télécharger depuis les pages SourceForge (voir figure 1-7) : - http://code.google.com/p/git-osx-installer + http://sourceforge.net/projects/git-osx-installer/ Insert 18333fig0107.png Figure 1-7. Installateur OS X de Git. @@ -268,7 +268,7 @@ Installer Git sur Windows est très facile. Le projet msysGit fournit une des procédures d'installation les plus simples. Téléchargez simplement le fichier exe d'installateur depuis la page GitHub, et lancez-le : - http://msysgit.github.com/ + http://msysgit.github.io Après son installation, vous avez à la fois la version en ligne de commande (avec un client SSH utile pour la suite) et l'interface graphique standard. @@ -291,10 +291,10 @@ Ces variables peuvent être stockées dans trois endroits différents : Si vous passez l'option `--system` à `git config`, il lit et écrit ce fichier spécifiquement. * Fichier `~/.gitconfig` : Spécifique à votre utilisateur. Vous pouvez forcer Git à lire et écrire ce fichier en passant l'option `--global`. -* Fichier `config` dans le répertoire Git (c'est à dire `.git/config`) du dépôt en cours d'utilisation : spécifique au seul dépôt en cours. +* Fichier `config` dans le répertoire Git (c'est-à-dire `.git/config`) du dépôt en cours d'utilisation : spécifique au seul dépôt en cours. Chaque niveau surcharge le niveau précédent, donc les valeurs dans `.git/config` surchargent celles de `/etc/gitconfig`. -Sur les systèmes Windows, Git recherche le fichier `.gitconfig` dans le répertoire `$HOME` (`%USERPROFILE%` dans l'environement natif de Windows) qui est `C:\Documents and Settings\$USER` ou `C:\Users\$USER` la plupart du temps, selon la version (`$USER` devient `%USERNAME%` dans l'environement de Windows). +Sur les systèmes Windows, Git recherche le fichier `.gitconfig` dans le répertoire `$HOME` (`%USERPROFILE%` dans l’environnement natif de Windows) qui est `C:\Documents and Settings\$USER` ou `C:\Users\$USER` la plupart du temps, selon la version (`$USER` devient `%USERNAME%` dans l’environnement de Windows). Il recherche tout de même `/etc/gitconfig`, bien qu'il soit relatif à la racine MSys, qui se trouve où vous aurez décidé d'installer Git sur votre système Windows. ### Votre identité ### diff --git a/fr/02-git-basics/01-chapter2.markdown b/fr/02-git-basics/01-chapter2.markdown index 8f1fe37c6..c7742c88d 100644 --- a/fr/02-git-basics/01-chapter2.markdown +++ b/fr/02-git-basics/01-chapter2.markdown @@ -80,8 +80,8 @@ L'outil principal pour déterminer quels fichiers sont dans quel état est la co Si vous lancez cette commande juste après un clonage, vous devriez voir ce qui suit : $ git status - # On branch master - nothing to commit (working directory clean) + On branch master + nothing to commit, working directory clean Ce message signifie que votre copie de travail est propre, en d'autres mots, aucun fichier suivi n'a été modifié. Git ne voit pas non plus de fichiers non-suivis, sinon ils seraient listés ici. @@ -94,11 +94,12 @@ Si ce fichier n'existait pas auparavant, et que vous lancez la commande `git sta $ vim LISEZMOI $ git status - # On branch master - # Untracked files: - # (use "git add ..." to include in what will be committed) - # - # LISEZMOI + On branch master + Untracked files: + (use "git add ..." to include in what will be committed) + + LISEZMOI + nothing added to commit but untracked files present (use "git add" to track) Vous pouvez constater que votre nouveau fichier `LISEZMOI` n'est pas en suivi de version, car il apparaît dans la section « Untracked files » de l'état de la copie de travail. @@ -116,12 +117,12 @@ Pour commencer à suivre le fichier `LISEZMOI`, vous pouvez entrer ceci : Si vous lancez à nouveau la commande `git status`, vous pouvez constater que votre fichier `LISEZMOI` est maintenant suivi et indexé : $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: LISEZMOI - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: LISEZMOI + Vous pouvez affirmer qu'il est indexé car il apparaît dans la section « Changes to be committed » (Modifications à valider). Si vous enregistrez à ce moment, la version du fichier à l'instant où vous lancez `git add` est celle qui appartiendra à l'instantané. @@ -134,17 +135,18 @@ Maintenant, modifions un fichier qui est déjà sous suivi de version. Si vous modifiez le fichier sous suivi de version appelé `benchmarks.rb` et que vous lancez à nouveau votre commande `git status`, vous verrez ceci : $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: LISEZMOI - # - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: LISEZMOI + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + Le fichier `benchmarks.rb` apparaît sous la section nommée « Changes not staged for commit » ce qui signifie que le fichier sous suivi de version a été modifié dans la copie de travail mais n'est pas encore indexé. Pour l'indexer, il faut lancer la commande `git add` (qui est une commande multi-usage — elle peut être utilisée pour placer un fichier sous suivi de version, pour indexer un fichier ou pour d'autres actions telles que marquer comme résolus des conflits de fusion de fichiers). @@ -152,13 +154,13 @@ Lançons maintenant `git add` pour indexer le fichier `benchmarks.rb`, et relan $ git add benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: LISEZMOI - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: LISEZMOI + modified: benchmarks.rb + À présent, les deux fichiers sont indexés et feront partie de la prochaine validation. Mais supposons que vous souhaitiez apporter encore une petite modification au fichier `benchmarks.rb` avant de réellement valider la nouvelle version. @@ -167,18 +169,19 @@ Néanmoins, vous lancez `git status` une dernière fois : $ vim benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: LISEZMOI - # modified: benchmarks.rb - # - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: LISEZMOI + modified: benchmarks.rb + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + Que s'est-il donc passé ? À présent, `benchmarks.rb` apparaît à la fois comme indexé et non indexé. En fait, Git indexe un fichier dans son état au moment où la commande `git add` est lancée. @@ -187,13 +190,13 @@ Si le fichier est modifié après un `git add`, il faut relancer `git add` pour $ git add benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: LISEZMOI - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: LISEZMOI + modified: benchmarks.rb + ### Ignorer des fichiers ### @@ -248,17 +251,18 @@ Supposons que vous éditez et indexez le fichier `LISEZMOI` et que vous éditez Si vous lancez la commande `git status`, vous verrez ceci : $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: LISEZMOI - # - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: LISEZMOI + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + Pour visualiser ce qui a été modifié mais pas encore indexé, tapez `git diff` sans autre argument : @@ -738,7 +742,9 @@ Cette commande fonctionne avec de nombreux formats — vous pouvez indiquer une Vous pouvez aussi restreindre la liste aux *commits* vérifiant certains critères de recherche. L'option `--author` permet de filtrer sur un auteur spécifique, et l'option `--grep` permet de chercher des mots clés dans les messages de validation. -Notez que si vous cherchez seulement des *commits* correspondant simultanément aux deux critères, vous devez ajouter l'option `--all-match`, car par défaut ces commandes retournent les *commits* vérifiant au moins un critère lors de recherche. +Notez que si vous spécifiez à la fois `--author` et `--grep`, la commande retournera seulement des *commits* correspondant simultanément aux deux critères. + +Si vous souhaitez spécifier plusieurs options `--grep`, vous devez ajouter l'option `--all-match`, car par défaut ces commandes retournent les *commits* vérifiant au moins un critère de recherche. La dernière option vraiment utile à `git log` est la spécification d'un chemin. Si un répertoire ou un nom de fichier est spécifié, le journal est limité aux *commits* qui ont introduit des modifications aux fichiers concernés. @@ -924,7 +930,7 @@ Par exemple, mon dépôt Grit ressemble à ceci. koke git://github.com/koke/grit.git origin git@github.com:mojombo/grit.git -Cela signifie que nous pouvons tirer très facilement des contributions depuis certains utilisateurs. +Cela signifie que je peux tirer très facilement des contributions depuis certains utilisateurs. Mais il est à noter que seul le dépôt distant `origin` utilise une URL SSH, ce qui signifie que c'est le seul sur lequel je peux pousser (nous traiterons de ceci au chapitre 4). ### Ajouter des dépôts distants ### @@ -1000,7 +1006,7 @@ Si vous lancez cette commande avec un nom court particulier, tel que `origin`, v ticgit -Cela donne le liste des URL pour le dépôt distant ainsi que la liste des branches distantes suivies. +Cela donne la liste des URL pour le dépôt distant ainsi que la liste des branches distantes suivies. Cette commande vous informe que si vous êtes sur la branche `master` et si vous lancez `git pull`, il va automatiquement fusionner la branche `master` du dépôt distant après avoir récupéré toutes les références sur le serveur distant. Cela donne aussi la liste des autres références qu'il aura tirées. @@ -1289,9 +1295,8 @@ De nombreuses personnes utilisent parfaitement Git sans connaître aucun de ces ### Auto-Complétion ### Si vous utilisez le shell Bash, Git est livré avec un script d'auto-complétion utile. -Téléchargez le code source de Git, et jetez un œil dans le répertoire `contrib/completion`. -Il devrait y avoir un fichier nommé `git-completion.bash`. -Copiez ce fichier dans votre répertoire personnel et ajoutez cette ligne à votre fichier `.bashrc` : +Téléchargez le directement depuis le code source de Git à https://github.com/git/git/blob/master/contrib/git-completion.bash . +Copiez ce fichier dans votre répertoire personnel sous le nom `.git-completion.bash` et ajoutez cette ligne à votre fichier `.bashrc` : source ~/.git-completion.bash diff --git a/fr/03-git-branching/01-chapter3.markdown b/fr/03-git-branching/01-chapter3.markdown index 6768e4a02..c6c7f1246 100644 --- a/fr/03-git-branching/01-chapter3.markdown +++ b/fr/03-git-branching/01-chapter3.markdown @@ -336,15 +336,20 @@ Placer le fichier dans l'index marque le conflit comme résolu pour Git. Si vous souhaitez utiliser un outil graphique pour résoudre ces problèmes, vous pouvez lancer `git mergetool` qui démarre l'outil graphique de fusion approprié et vous permet de naviguer dans les conflits : $ git mergetool - merge tool candidates: kdiff3 tkdiff xxdiff meld gvimdiff opendiff emerge vimdiff - Merging the files: index.html + + This message is displayed because 'merge.tool' is not configured. + See 'git mergetool --tool-help' or 'git help config' for more details. + 'git mergetool' will now attempt to use one of the following tools: + opendiff kdiff3 tkdiff xxdiff meld tortoisemerge gvimdiff diffuse diffmerge ecmerge p4merge araxis bc3 codecompare vimdiff emerge + Merging: + index.html Normal merge conflict for 'index.html': - {local}: modified - {remote}: modified + {local}: modified file + {remote}: modified file Hit return to start merge resolution tool (opendiff): -Si vous souhaitez utiliser un outil de fusion autre que celui par défaut (Git a choisi `opendiff` pour moi dans ce cas car j'utilise la commande sous Mac), vous pouvez voir tous les outils supportés après l'indication « merge tool candidates ». +Si vous souhaitez utiliser un outil de fusion autre que celui par défaut (Git a choisi `opendiff` pour moi dans ce cas car j'utilise la commande sous Mac), vous pouvez voir tous les outils supportés après l'indication « *of the following tools:* ». Tapez le nom de l'outil que vous préfèreriez utiliser. Au chapitre 7, nous expliquerons comment changer cette valeur par défaut dans votre environnement. @@ -579,7 +584,7 @@ Cette commande vous fournit une branche locale modifiable basée sur l'état act L'extraction d'une branche locale à partir d'une branche distante crée automatiquement ce qu'on appelle une _branche de suivi_. Les branches de suivi sont des branches locales qui sont en relation directe avec une branche distante. Si vous vous trouvez sur une branche de suivi et que vous tapez `git push`, Git sélectionne automatiquement le serveur vers lequel pousser vos modifications. -De même, `git pull` sur une de ces branches récupère toutes les références distantes et les fusionne automatiquement dans la branche distante correspondante. +De même, `git pull` sur une de ces branches récupère toutes les références distantes et fusionne automatiquement la branche distante correspondante dans la branche actuelle. Lorsque vous clonez un dépôt, il crée généralement automatiquement une branche `master` qui suit `origin/master`. C'est pourquoi les commandes `git push` et `git pull` fonctionnent directement sans plus de paramétrage. @@ -597,7 +602,7 @@ Pour créer une branche locale avec un nom différent de celui de la branche dis Branch sf set up to track remote branch refs/remotes/origin/correctionserveur. Switched to a new branch "sf" -À présent, votre branche locale sf poussera vers et tirera automatiquement depuis origin/correctionserveur. +À présent, votre branche locale `sf` poussera vers et tirera automatiquement depuis `origin/correctionserveur`. ### Effacer des branches distantes ### diff --git a/fr/04-git-server/01-chapter4.markdown b/fr/04-git-server/01-chapter4.markdown index 0ecbaf05f..5d68cb7bb 100644 --- a/fr/04-git-server/01-chapter4.markdown +++ b/fr/04-git-server/01-chapter4.markdown @@ -43,7 +43,8 @@ Ou bien cela : $ git clone file:///opt/git/projet.git Git opère légèrement différemment si vous spécifiez explicitement le protocole `file://` au début de l'URL. -Si vous spécifiez simplement le chemin, Git tente d'utiliser des liens durs ou une copie des fichiers nécessaires. +Si vous spécifiez simplement le chemin et si la destination se trouve sur le même système de fichiers, Git tente d'utiliser des liens physiques pour le fichiers communs. +Si la destination se trouve sur un autre système de fichiers, Git fait une copie des fichiers nécessaires. Si vous spécifiez le protocole `file://`, Git lance un processus d'accès au travers du réseau, ce qui est généralement moins efficace. La raison d'utiliser spécifiquement le préfixe `file://` est la volonté d'obtenir une copie propre du dépôt, sans aucune référence ou aucun objet supplémentaire qui pourraient résulter d'un import depuis un autre système de gestion de version ou d'une action similaire (voir chapitre 9 pour les tâches de maintenance). Nous utiliserons les chemins normaux par la suite car c'est la méthode la plus efficace. @@ -109,7 +110,7 @@ Si vous souhaitez proposer de l'accès anonyme en lecture seule à vos projets, ### Protocole Git ### Vient ensuite le protocole Git. Celui-ci est géré par un *daemon* spécial livré avec Git. Ce *daemon* (démon, processus en arrière plan) écoute sur un port dédié (9418) et propose un service similaire au protocole SSH, mais sans aucune sécurisation. -Pour qu'un dépôt soit publié via le protocole Git, le fichier `git-export-daemon-ok` doit exister mais mise à part cette condition sans laquelle le *daemon* refuse de publier un projet, il n'y a aucune sécurité. +Pour qu'un dépôt soit publié via le protocole Git, le fichier `git-daemon-export-ok` doit exister mais mise à part cette condition sans laquelle le *daemon* refuse de publier un projet, il n'y a aucune sécurité. Soit le dépôt Git est disponible sans restriction en lecture, soit il n'est pas publié. Cela signifie qu'il ne permet pas de pousser des modifications. Vous pouvez activer la capacité à pousser mais étant donné l'absence d'authentification, n'importe qui sur Internet ayant trouvé l'URL du projet peut pousser sur le dépôt. @@ -514,7 +515,7 @@ Il faut donc installer le paquet Python setuptools qu'Ubuntu fournit en tant que Ensuite, il faut cloner et installer Gitosis à partir du site principal du projet : - $ git clone git://eagain.net/gitosis.git + $ git clone https://github.com/tv42/gitosis.git $ cd gitosis $ sudo python setup.py install @@ -982,7 +983,7 @@ Nous allons détailler comment faire. ### Création d'un compte utilisateur ### La première chose à faire, c'est de créer un compte utilisateur gratuit. -Visitez la page « Plans & Pricing » (plans et prix) à `http://github.com/plans` et cliquez sur le bouton « Create a free account » (créer un compte gratuit) de la zone « Free for open source » (gratuit pour l'open source) (voir figure 4-2) qui vous amène à la page d'enregistrement. +Visitez la page « Plans and pricing » (plans et prix) à `https://github.com/pricing` et cliquez sur le bouton « Create a free account » (créer un compte gratuit) de la zone « Free for open source » (gratuit pour l'open source) (voir figure 4-2) qui vous amène à la page d'enregistrement. Insert 18333fig0402.png Figure 4-2. La page des différents plans de GitHub. diff --git a/fr/05-distributed-git/01-chapter5.markdown b/fr/05-distributed-git/01-chapter5.markdown index 19716edfd..8b0ac0a35 100644 --- a/fr/05-distributed-git/01-chapter5.markdown +++ b/fr/05-distributed-git/01-chapter5.markdown @@ -255,7 +255,7 @@ John a une référence aux modifications que Jessica a poussées, mais il doit l Cette fusion se passe sans problème — l'historique de *commits* de John ressemble à présent à la figure 5-5. Insert 18333fig0505.png -Figure 5-5. Le dépôt local de John après la fusion d'origin/master. +Figure 5-5. Le dépôt local de John après la fusion d'`origin/master`. Maintenant, John peut tester son code pour s'assurer qu'il fonctionne encore correctement et peut pousser son travail nouvellement fusionné sur le serveur : @@ -678,11 +678,31 @@ Vous pouvez positionner ces valeurs séparément avec une série de commandes `g sslverify = false Si votre serveur IMAP n'utilise pas SSL, les deux dernières lignes ne sont probablement pas nécessaires et le paramètre `host` commencera par `imap://` au lieu de `imaps://`. -Quand c'est fait, vous pouvez utiliser la commande `git send-email` pour placer la série de patchs dans le répertoire *Drafts* du serveur IMAP spécifié : +Quand c'est fait, vous pouvez utiliser la commande `git imap-send` pour placer la série de patchs dans le répertoire *Drafts* du serveur IMAP spécifié : + + $ cat *.patch |git imap-send + Resolving imap.gmail.com... ok + Connecting to [74.125.142.109]:993... ok + Logging in... + sending 2 messages + 100% (2/2) done + +À présent, vous devriez pouvoir vous rendre dans le répertoire *Drafts*, changer le champ destinataire pour celui de la liste de diffusion, y ajouter optionnellement en copie le mainteneur du projet ou le responsable et l'envoyer. + +Une autre méthode consiste à envoyer vos patchs par un serveur SMTP. +Comme précédemment, vous pouvez régler chaque paramètre séparément avec une série de commandes `git config` ou vous pouvez les ajouter directement dans la section `sendemail` de votre fichier `~/.gitconfig` : + + [sendemail] + smtpencryption = tls + smtpserver = smtp.gmail.com + smtpuser = user@gmail.com + smtpserverport = 587 + +Après ceci, vous pouvez utiliser la commande `git send-email` pour envoyer vos patchs : $ git send-email *.patch - 0001-Ajout-d-une-limite-la-fonction-de-log.patch - 0002-change-la-largeur-du-log-de-25-a-30.patch + 0001-added-limit-to-log-function.patch + 0002-changed-log-output-to-30-from-25.patch Who should the emails appear to be from? [Jessica Smith ] Emails will be sent from: Jessica Smith Who should the emails be sent to? jessica@example.com @@ -707,8 +727,6 @@ Ensuite, Git crache un certain nombre d'informations qui ressemblent à ceci pou Result: OK -À présent, vous devriez pouvoir vous rendre dans le répertoire Drafts, changer le champ destinataire pour celui de la liste de diffusion, y ajouter optionnellement en copie le mainteneur du projet ou le responsable et l'envoyer. - ### Résumé ### Ce chapitre a traité quelques-unes des méthodes communes de gestion de types différents de projets Git que vous pourrez rencontrer et a introduit un certain nombre de nouveaux outils pour vous aider à gérer ces processus. diff --git a/fr/06-git-tools/01-chapter6.markdown b/fr/06-git-tools/01-chapter6.markdown index 1fe8e5f19..07adf11d4 100644 --- a/fr/06-git-tools/01-chapter6.markdown +++ b/fr/06-git-tools/01-chapter6.markdown @@ -70,7 +70,7 @@ Si vous essayez de récupérer l'objet de nouveau à un moment donné, vous auri Quoi qu'il en soit, vous devriez être conscient à quel point ce scénario est ridiculement improbable. Une empreinte SHA-1 porte sur 20 octets soit 160 bits. -Le nombre d'objets aléatoires à hacher requis pour assurer une probabilité de collision de 50 % vaut environ 2^80 (la formule pour calculer la probabilité de collision est `p = (n(n-1)/2) * (1/2^160))`. +Le nombre d'objets aléatoires à hacher requis pour assurer une probabilité de collision de 50 % vaut environ 2^80 (la formule pour calculer la probabilité de collision est `p = (n(n-1)/2) * (1/2^160)`). 2^80 vaut 1,2 × 10^24 soit 1 million de milliards de milliards. Cela représente 1200 fois le nombre de grains de sable sur Terre. @@ -504,7 +504,7 @@ Votre répertoire de travail est propre : $ git status # On branch master - nothing to commit (working directory clean) + nothing to commit, working directory clean À ce moment, vous pouvez facilement changer de branche et travailler autre part ; vos modifications sont conservées dans votre pile. Pour voir quelles remises vous avez sauvegardées, vous pouvez utiliser la commande `git stash list` : @@ -577,7 +577,7 @@ La création d'un alias permettra d'ajouter effectivement la commande `stash-una Par exemple : $ git config --global alias.stash-unapply '!git stash show -p | git apply -R' - $ git stash + $ git stash apply $ #... work work work $ git stash-unapply @@ -1316,7 +1316,7 @@ Si vous récupérez l'une puis l'autre branche, vous pouvez voir que vous avez d Pour tirer le projet Rack dans votre projet `master` comme un sous-répertoire, vous pouvez utiliser la commande `git read-tree`. Vous apprendrez davantage sur `read-tree` et compagnie dans le chapitre 9, mais pour le moment, sachez qu'il lit la racine d'une de vos branches et l'inscrit dans votre index et votre répertoire de travail. -Vous venez juste de commuter vers votre branche `master` et vous tirez la branche `rack` vers le sous-répertoire `rack` de votre branche `master` de votre projet principal : +Vous venez juste de commuter vers votre branche `master` et vous tirez la branche `rack_branch` vers le sous-répertoire `rack` de votre branche `master` de votre projet principal : $ git read-tree --prefix=rack/ -u rack_branch diff --git a/fr/07-customizing-git/01-chapter7.markdown b/fr/07-customizing-git/01-chapter7.markdown index e7248a28a..8adb59f99 100644 --- a/fr/07-customizing-git/01-chapter7.markdown +++ b/fr/07-customizing-git/01-chapter7.markdown @@ -177,7 +177,7 @@ Pour Windows, vous devrez changer `/usr/local/bin` en un chemin d'exécution d'u Vous pouvez télécharger P4Merge ici : - http://www.perforce.com/perforce/downloads/component.html + http://www.perforce.com/product/components/perforce-visual-merge-and-diff-tools Pour commencer, créez un script d'appel externe pour lancer vos commandes. Je vais utiliser le chemin Mac pour l'exécutable ; dans d'autres systèmes, il résidera où votre binaire `p4merge` a été installé. @@ -385,12 +385,23 @@ Dans la branche 1.6 de Git, vous pouvez aussi utiliser une macro fournie qui sig #### Comparaison de fichiers binaires #### -Dans la branche 1.6 de Git, vous pouvez utiliser la fonctionnalité des attributs Git pour effectivement comparer les fichiers binaires. +Dans Git, vous pouvez utiliser la fonctionnalité des attributs pour comparer efficacement les fichiers binaires. Pour ce faire, indiquez à Git comment convertir vos données binaires en format texte qui peut être comparé via un diff normal. +Mais le question revient alors à savoir comment convertir les données binaires en texte. +La meilleure solution consiste à trouver un outil qui réalise pour vous la conversion des données binaires en représentation textuelle (imaginez par exemple comment convertir un fichier audio en texte). +Si c'est impossible et qur vous ne parvenez pas à obtenir une réprésentation du contenu sous forme de texte, il reste relativement facile d'obtenir une description dans un format humainement lisible de ce contenu. +Les métadonnées ne vous donneront pas une représentation complète du contenu du fichier, mais c'est en tout cas mieux que rien. + +Nous allons utiliser les deux méthodes précédentes pour obtenir des comparaisons de formats binaires largement utilisés. + +Note : il existe de nombreux types de formats binaires avec du contenu textuel pour lesquels il est difficile de trouver une convertisseur vers du texte. +Dans ces cas, il reste toujours possible d'extraire le texte au moyen du programme `strings`. +Certains de ces fichiers peuvent aussi utiliser une encodage spécifique du texte, comme UTF-16, et `strings` ne trouvera alors rien de probant. +Les résultats sont très variables. +Dans tous les cas, `strings` est disponible sur la plupart des systèmes Mac et Linux, et constitue une bonne option pour un premier essai. ##### Fichiers MS Word ##### -Comme c'est une fonctionnalité plutôt cool et peu connue, nous allons en voir quelques exemples. Premièrement, nous utiliserons cette technique pour résoudre un des problèmes les plus ennuyeux de l'humanité : gérer en contrôle de version les documents Word. Tout le monde convient que Word est l'éditeur de texte le plus horrible qui existe, mais bizarrement, tout le monde persiste à l'utiliser. Si vous voulez gérer en version des documents Word, vous pouvez les coller dans un dépôt Git et les valider de temps à autre. @@ -411,20 +422,17 @@ Ajoutez la ligne suivante dans votre fichier `.gitattributes` : Cette ligne indique à Git que tout fichier correspondant au patron (.doc) doit utiliser le filtre `word` pour visualiser le diff des modifications. Qu'est-ce que le filtre « word » ? Nous devons le définir. -Vous allez configurer Git à utiliser le programme `strings` pour convertir les documents Word en fichiers texte lisibles qu'il pourra alors comparer correctement : +Vous allez indiquer à Git d'utiliser le programme `catdoc` qui a été écrit spécifiquement pour extraire le texte d'un document MS Word. +Vous pouvez l'obtenir depuis `http://www.wagner.pp.ru/~vitus/software/catdoc`. - $ git config diff.word.textconv strings + $ git config diff.word.textconv catdoc Cette commande ajoute à votre fichier `.git/config` une section qui ressemble à ceci : [diff "word"] - textconv = strings - -Note : il existe différents types de fichiers `.doc`. -Certains utilisent un codage UTF-16 ou d'autres pages de codes plus exotiques dans lesquels `strings` ne trouvera aucune chaîne utile. -Le résultat de ce filtre pour vos fichiers dépendra de ces conditions. + textconv = catdoc -À présent, Git sait que s'il essaie de faire un diff entre deux instantanés et qu'un des fichiers finit en `.doc`, il devrait faire passer ces fichiers par le filtre `word` défini comme le programme `strings`. +À présent, Git sait que s'il essaie de faire un diff entre deux instantanés et qu'un des fichiers finit en `.doc`, il devrait faire passer ces fichiers par le filtre `word` défini comme le programme `catdoc`. Cette méthode fait effectivement des jolies versions texte de vos fichiers Word avant d'essayer de les comparer. Voici un exemple. @@ -436,18 +444,14 @@ Puis, j'ai lancé `git diff` pour visualiser ce qui a changé : index c1c8a0a..b93c9e4 100644 --- a/chapter1.doc +++ b/chapter1.doc - @@ -8,7 +8,8 @@ re going to cover Version Control Systems (VCS) and Git basics - re going to cover how to get it and set it up for the first time if you don - t already have it on your system. - In Chapter Two we will go over basic Git usage - how to use Git for the 80% - -s going on, modify stuff and contribute changes. If the book spontaneously - +s going on, modify stuff and contribute changes. If the book spontaneously - +Let's see if this works. - -Git réussit à m'indiquer succinctement que j'ai ajouté la chaîne « *Let's see if this works* », ce qui est correct. -Ce n'est pas parfait car il y a toujours un tas de données aléatoires à la fin, mais c'est suffisant. -Si vous êtes capable d'écrire un convertisseur Word vers texte qui fonctionne suffisamment bien, cette solution peut s'avérer très efficace. -Cependant, `strings` est disponible sur la plupart des systèmes Mac et Linux et peut donc constituer un bon début pour de nombreux formats binaires. + @@ -128,7 +128,7 @@ and data size) + Since its birth in 2005, Git has evolved and matured to be easy to use + and yet retain these initial qualities. It’s incredibly fast, it’s + very efficient with large projects, and it has an incredible branching + -system for non-linear development. + +system for non-linear development (See Chapter 3). + +Git m'indique succinctement que j'ai ajouté la chaîne « (see Chapter 3) », ce qui est correct. ##### Fichiers OpenDocument texte ##### diff --git a/fr/08-git-and-other-scms/01-chapter8.markdown b/fr/08-git-and-other-scms/01-chapter8.markdown index e7e3ad7ac..f31bf8d22 100644 --- a/fr/08-git-and-other-scms/01-chapter8.markdown +++ b/fr/08-git-and-other-scms/01-chapter8.markdown @@ -456,7 +456,7 @@ Vous pouvez alors fournir ce fichier à `git svn` pour l'aider à convertir les Vous pouvez aussi indiquer à `git svn` de ne pas inclure les méta-données que Subversion importe habituellement en passant l'option `--no-metadata` à la commande `clone` ou `init`. Au final, votre commande d'import ressemble à ceci : - $ git-svn clone http://mon-projet.googlecode.com/svn/ \ + $ git svn clone http://mon-projet.googlecode.com/svn/ \ --authors-file=users.txt --no-metadata -s my_project Maintenant, l'import depuis Subversion dans le répertoire `my_project` est plus présentable. diff --git a/fr/09-git-internals/01-chapter9.markdown b/fr/09-git-internals/01-chapter9.markdown index ccf9eb886..9e881901d 100644 --- a/fr/09-git-internals/01-chapter9.markdown +++ b/fr/09-git-internals/01-chapter9.markdown @@ -544,7 +544,7 @@ Ajoutons de plus gros contenu au dépôt pour montrer une fonctionnalité intér Ajoutez le fichier `repo.rb` de la bibliothèque Grit que vous avez manipulé plus tôt. Il représente environ 12 Kio de code source : - $ curl https://raw.github.com/mojombo/grit/master/lib/grit/repo.rb > repo.rb + $ curl -L https://raw.github.com/mojombo/grit/master/lib/grit/repo.rb > repo.rb $ git add repo.rb $ git commit -m 'added repo.rb' [master 484a592] added repo.rb diff --git a/fr/README.md b/fr/README.md index 75cf1f4f3..4e8bfe586 100644 --- a/fr/README.md +++ b/fr/README.md @@ -2,10 +2,8 @@ ## Dépôt de référence ## -Le dépot de référence de la traduction française est situé ici : -https://github.com/progit-fr/progit - -C'est le dépôt de fusion des travaux sur la branche fr, avant de lancer les requêtes de tirage sur le dépôt principal Progit. +Comme le mainteneur des traductions du livre est français, le dépot de référence de la traduction française est situé ici. +https://github.com/progit/progit ## Liste de diffusion ## @@ -15,7 +13,7 @@ Si vous travaillez ou souhaitez travailler sur la traduction française de Progi ## Workflow ## -Pour simplifier la gestion et utiliser pleinement les capacités de Git et Github, la manière la plus directe de collaborer consiste à faire un fork sur Github du dépôt progit-fr/progit sur votre propre compte pour y générer vos modifications, si possible sur une branche thématique. +Pour simplifier la gestion et utiliser pleinement les capacités de Git et Github, la manière la plus directe de collaborer consiste à faire un fork sur Github du dépôt progit/progit sur votre propre compte pour y générer vos modifications, si possible sur une branche thématique. Ensuite, il suffit de lancer une requête de tirage pour nous avertir que les modifications peuvent être revues et intégrées. diff --git a/hi/01-introduction/01-chapter1.markdown b/hi/01-introduction/01-chapter1.markdown new file mode 100644 index 000000000..1c3a27f67 --- /dev/null +++ b/hi/01-introduction/01-chapter1.markdown @@ -0,0 +1,7 @@ +# शुरुआत # + +यह अध्याय गिट के साथ कैसे शुरुआत की जाए की व्याख्या करेगा। सर्वप्रथम हम संस्करण नियंत्रण (version control) के साधनों की पृष्ठभूमि पे एक नज़र डालेंगे, इसके बाद गिट को कैसे किसी सिस्टम में इंस्टॉल करना है ये बताया जायेगा और फिर कैसे सेटअप पूरा कर इसके साथ काम करना है बताया जाएगा। इस अध्याय के आखिरी हिस्से से स्पष्टीकरण मिलेगा कि गिट क्यों बनाया गया और आपको इसका इस्तेमाल क्यों करना चाहिए, जिसके समर्थ आप तब तक हो चुके होंगे। + +## संस्करण नियंत्रण ## + +संस्करण नियंत्रण (version control) क्या है और इसके बारे में पता होना किसलिए मददगार है? संस्करण नियंत्रण (version control) एक पद्धति है जो समय के साथ किसी फ़ाइल या फ़ाइल समूह में होने वाले परिवर्तनों को याद रखती है जिसका प्रयोग करके आप उनकी किसी पूर्ण अवस्था का बाद में परीक्षण कर सकते हैं। यद्यपि इस पुस्तक के उदाहरण सॉफ्टवेयर फाइल्स का प्रयोग करके संस्करण नियंत्रण का प्रदर्शन करते हैं, वास्तविकता में किसी भी प्रकार की फ़ाइल ऐसे सिस्टम में रखी जा सकती है। diff --git a/hu/01-introduction/01-chapter1.markdown b/hu/01-introduction/01-chapter1.markdown index d05aca1fc..7f314fc2b 100644 --- a/hu/01-introduction/01-chapter1.markdown +++ b/hu/01-introduction/01-chapter1.markdown @@ -8,7 +8,7 @@ Mi az a verziókövetés, és miért kellene vele törődnünk? A verziókövet Ha grafikus vagy webdizájner vagy és meg akarod tartani az összes verzióját egy képnek vagy egy weboldal tervezetnek (amit mindenképp szeretnél), egy Verziókövető Rendszer (VR) legalkalmasabb dolog a feladatra. Lehetővé teszi fájlok visszaálítást egy előző verzióra, a teljes projekt visszaállítását egy előző verzióra, változatok összehasonlítását bármely idő intervalimra, rájöhetsz miért okoz az utolsó módsításod problémát, hogyan keletkezik egy esemény és miért és így tovább. A VR használata az is jelenti ha elrontasz valamit vagy elveszne egy fájl könnyedén visszavonhatod minimális erőforrás ráfordítással. -### Egyéni verziókövető rendszerk ### +### Egyéni verziókövető rendszerek ### Sok ember választja verziókövető megoldásnak a fájlok különböző mappákba másolását (mappák neve egy időbélyeg ha értelmesen csinálják). Ez a legkönnyebben befogadható megoldás mert egyszerű, de hihetetlenül könnyű hibázni. Elfelejtik hogy melyik mappában vannak rossz fájlt írnak vagy írnakfelül olyat amit nem kellett volna. @@ -32,7 +32,7 @@ Ugyanakkor ez az összeállításnak van néhány komoly hátránya. A legnyílv ### Elosztott verziókövető rendszerek ### -Ekkor jöttek az Elosztott Verziókövető Rendszerek (EVR). Az EVR-ekben, mint a Git, a Mercurical, a Bazaar vagy a Dracs, a kliensek nem csak a legutolsó állapotot kérik le, hanem a teljes repositorit. Ekéépen ha a szerver megáll, amin eddig folyt az együttműködés, bármelyik kliens repositoriból vissza állítható a teljes adatbázis. Minden adat lekrés tényleg teljes mentésnek felel meg (Lásd 1-3 ábra). +Ekkor jöttek az Elosztott Verziókövető Rendszerek (EVR). Az EVR-ekben, mint a Git, a Mercurical, a Bazaar vagy a Dracs, a kliensek nem csak a legutolsó állapotot kérik le, hanem a teljes repositorit. Ekéépen ha a szerver megáll, amin eddig folyt az együttműködés, bármelyik kliens repositoriból vissza állítható a teljes adatbázis. Minden adat lekérés tényleg teljes mentésnek felel meg (Lásd 1-3 ábra). Insert 18333fig0103.png 1-3 ábra. Elosztott verziókövetés sematikus ábrája. @@ -161,9 +161,9 @@ Or if you’re on a Debian-based distribution like Ubuntu, try apt-get: ### Installing on Mac ### -There are two easy ways to install Git on a Mac. The easiest is to use the graphical Git installer, which you can download from the Google Code page (see Figure 1-7): +There are two easy ways to install Git on a Mac. The easiest is to use the graphical Git installer, which you can download from the SourceForge page (see Figure 1-7): - http://code.google.com/p/git-osx-installer + http://sourceforge.net/projects/git-osx-installer/ Insert 18333fig0107.png Figure 1-7. Git OS X installer. diff --git a/id/01-introduction/01-chapter1.markdown b/id/01-introduction/01-chapter1.markdown index af9b8cfc3..8fe56b1e6 100644 --- a/id/01-introduction/01-chapter1.markdown +++ b/id/01-introduction/01-chapter1.markdown @@ -161,9 +161,9 @@ Atau jika anda menggunakan distro berbasis Debian seperti Ubuntu, coba gunakan a ### Menginstall Git pada Mac ### -Terdapat dua cara mudah untuk menginstal Git pada sebuah komputer Mac. Cara termudah adalah menggunakan installer Git berbasis GUI, yang dapat anda peroleh dari halaman Google Code (lihat Gambar 1-7): +Terdapat dua cara mudah untuk menginstal Git pada sebuah komputer Mac. Cara termudah adalah menggunakan installer Git berbasis GUI, yang dapat anda peroleh dari halaman SourceForge (lihat Gambar 1-7): - http://code.google.com/p/git-osx-installer + http://sourceforge.net/projects/git-osx-installer/ Insert 18333fig0107.png Gambar 1-7. Git OS X installer. diff --git a/id/02-git-basics/01-chapter2.markdown b/id/02-git-basics/01-chapter2.markdown index dd67c0367..428e91669 100644 --- a/id/02-git-basics/01-chapter2.markdown +++ b/id/02-git-basics/01-chapter2.markdown @@ -55,7 +55,7 @@ Alat utama yang Anda gunakan untuk menentukan berkas-berkas mana yang berada dal $ git status # On branch master - nothing to commit (working directory clean) + nothing to commit, working directory clean Ini berarti Anda memiliki direktori kerja yang bersih-dengan kata lain, tidak ada berkas terpantau yang terubah. Git juga tidak melihat berkas-berkas yang tak terpantau, karena pasti akan dilaporkan oleh alat ini. Juga, perintah ini memberitahu Anda tentang cabang tempat Anda berada. Pada saat ini, cabang akan selalu berada di master, karena sudah menjadi default-nya; Anda tidak perlu khawatir tentang cabang dulu. Bab berikutnya akan membahas tentang percabangan dan referensi secara lebih detil. diff --git a/id/03-git-branching/01-chapter3.markdown b/id/03-git-branching/01-chapter3.markdown index 3762d0418..db3b55e30 100644 --- a/id/03-git-branching/01-chapter3.markdown +++ b/id/03-git-branching/01-chapter3.markdown @@ -92,61 +92,61 @@ Hal ini kontras dengan cara yang dilakukan banyak VCS dalam branch, yang butuh m Mari kita lihat mengapa anda harus melakukannya. -## Basic Branching and Merging ## +## Dasar Pencabangan (Branching) dan Penggabungan (Merging) ## -Let’s go through a simple example of branching and merging with a workflow that you might use in the real world. You’ll follow these steps: +Mari kita lihat contoh sederhana dari Pencabangan dan Penggabungan dengan diagram alir yang biasa kita gunakan secara nyata. Anda akan mengikut tahapan berikut : -1. Do work on a web site. -2. Create a branch for a new story you’re working on. -3. Do some work in that branch. +1. Bekerja di jejaring (website). +2. Buat pencabangan untuk hal baru yang sedang dikerjakan. +3. Bekerja di pencabangan tersebut. -At this stage, you’ll receive a call that another issue is critical and you need a hotfix. You’ll do the following: +Pada tahap ini, anda akan menerima pesan bahwa ada masalah yang kritis dan anda perlu memperbaikinya. Anda akan melakukan tahapan berikut : -1. Revert back to your production branch. -2. Create a branch to add the hotfix. -3. After it’s tested, merge the hotfix branch, and push to production. -4. Switch back to your original story and continue working. +1. Kembali ke pencabangan saat produksi. +2. Membuat pencabangan untuk memperbaiki masalah. +3. Setelah diuji, gabungkan pencabangan perbaikan tadi, dan tempatkan di bagian produksi. +4. Kembali ke kasus sebelumnya dan kembali bekerja. -### Basic Branching ### +### Dasar Pencabangan ### -First, let’s say you’re working on your project and have a couple of commits already (see Figure 3-10). +Pertama, katakan anda sedang mengerjakan sebuah proyek dan telah melakukan *commits* (lihat Gambar 3-10). Insert 18333fig0310.png -Figure 3-10. A short and simple commit history. +Gambar 3-10. Sejarah *commit* yang pendek dan sederhana. -You’ve decided that you’re going to work on issue #53 in whatever issue-tracking system your company uses. To be clear, Git isn’t tied into any particular issue-tracking system; but because issue #53 is a focused topic that you want to work on, you’ll create a new branch in which to work. To create a branch and switch to it at the same time, you can run the `git checkout` command with the `-b` switch: +Anda memutuskan untuk mengerjakan masalah #53 pada apapun jenis sistem pelacak-masalah yang digunakan perusahaan. Untuk memperjelas, Git tidak terikat dengan sistem pelacak-masalah apapun; tapi karena masalah #53 adalah inti topik yang akan dikerjakan, anda akan membuat pencabangan dimana anda bekerja. Untuk membuat pencabangan dan berpindah kesana dalam satu waktu, anda dapat menjalankan perintah `git checkout` dengan tanda `-b` : $ git checkout -b iss53 Switched to a new branch "iss53" -This is shorthand for: +Ini adalah bentuk singkat untuk : $ git branch iss53 $ git checkout iss53 -Figure 3-11 illustrates the result. +Gambar 3-11 menjelaskan hasilnya. Insert 18333fig0311.png -Figure 3-11. Creating a new branch pointer. +Gambar 3-11. Membuat penunjuk baru pencabangan. -You work on your web site and do some commits. Doing so moves the `iss53` branch forward, because you have it checked out (that is, your HEAD is pointing to it; see Figure 3-12): +Anda bekerja di jejaring *website* dan melakukan beberapa *commits*. Dengan melakukannya, menggeser cabang `iss53` kedepan, karena anda menyelesaikannya (demikianlah, HEAD anda penunjuk ke sana; lihat Gambar 3-12) : $ vim index.html $ git commit -a -m 'added a new footer [issue 53]' Insert 18333fig0312.png -Figure 3-12. The iss53 branch has moved forward with your work. +Gambar 3-12. Cabang iss53 telah bergerak kedepan sesuai pekerjaan anda. -Now you get the call that there is an issue with the web site, and you need to fix it immediately. With Git, you don’t have to deploy your fix along with the `iss53` changes you’ve made, and you don’t have to put a lot of effort into reverting those changes before you can work on applying your fix to what is in production. All you have to do is switch back to your master branch. +Lalu kemudian, saat kita melihat ada permasalahan dalam situs jejaring, dan kita perlu untuk memperbaikinya segera. Dengan Git, anda tidak perlu memasang pembetulannya bersama dengan perubahan di `iss53`, dan anda tidak perlu melakukan cara yang sulit untuk kembali ke pekerjaan anda sebelumnya di tahap produksi. Yang anda perlukan hanya kembali ke pencabangan *master*. -However, before you do that, note that if your working directory or staging area has uncommitted changes that conflict with the branch you’re checking out, Git won’t let you switch branches. It’s best to have a clean working state when you switch branches. There are ways to get around this (namely, stashing and commit amending) that we’ll cover later. For now, you’ve committed all your changes, so you can switch back to your master branch: +Bagaimanapun, sebelum anda melakukannya, perhatikan bahwa jika dalam kandar kerja anda atau kondisi *staging* memiliki perubahan yang bertentangan dengan pencabangan yang akan anda tinggalkan, Git tidak akan memperbolehkan anda berpindah. Ini adalah cara terbaik untuk meninggalkan pekerjaan dalam keadaan bersih ketika anda akan berpindah pencabangan. Ada beberapa cara untuk melakukan ini (*namely*, *stashing*, dan merubah *commit*) yang akan kita bahas berikutnya. Untuk saat ini, anda telah *commit* seluruh perubahan, sehingga anda dapat kembali ke pencabangan *master*: $ git checkout master Switched to branch "master" -At this point, your project working directory is exactly the way it was before you started working on issue #53, and you can concentrate on your hotfix. This is an important point to remember: Git resets your working directory to look like the snapshot of the commit that the branch you check out points to. It adds, removes, and modifies files automatically to make sure your working copy is what the branch looked like on your last commit to it. +Saat ini, anda berada dalam kandar kerja dalam kondisi tepat seperti anda belum mengerjakan masalah #53, dan anda dapat konsentrasi mengerjakan perbaikannya. Hal yang perlu diingat adalah: Git mengkondisikan kandar kerja anda agar terlihat sebagaimana anda kembali ke titik pencabangan yang anda tuju. Git menambahkan, menghapus, dan mengubah berkas secara otomatis untuk memastikan bahwa anda bekerja pada pencabangan terakhir yang anda *commit*. -Next, you have a hotfix to make. Let’s create a hotfix branch on which to work until it’s completed (see Figure 3-13): +Selanjutnya, ada dapat membuat cabang *hotfix*. Mari kita buat cabang *hotfix* tempat kita bekerja sampai kondisinya selesai (lihat Gambar 3-13): $ git checkout -b 'hotfix' Switched to a new branch "hotfix" diff --git a/it/01-introduction/01-chapter1.markdown b/it/01-introduction/01-chapter1.markdown index 17c55c7a7..18a222ff6 100644 --- a/it/01-introduction/01-chapter1.markdown +++ b/it/01-introduction/01-chapter1.markdown @@ -1,132 +1,132 @@ # Per Iniziare # -Questo capitolo spiegherà come iniziare ad usare Git. Inizieremo con una introduzione sugli strumenti di controllo della versione, per poi passare a come far funzionare Git sul proprio sistema ed infine come configurarlo per lavorarci. Alla fine di questo capitolo, dovresti capire a cosa serve Git, perché lo dovresti usare ed essere pronto ad usarlo. +Questo capitolo spiegherà come iniziare ad usare Git. Inizieremo con una introduzione sugli strumenti per il controllo delle versioni, per poi passare a come far funzionare Git sul proprio sistema e quindi come configurarlo per lavorarci. Alla fine di questo capitolo, dovresti capire a cosa serve Git, perché dovresti usarlo e dovresti essere pronto ad usarlo. ## Il Controllo di Versione ## -Cos'è il controllo di versione, e perché dovresti usarlo? Il controllo di versione è un sistema che registra i cambiamenti ad un file o ad una serie di file nel tempo, così da poter richiamare una versione specifica successivamente. Per gli esempi in questo libro, useremo i file del codice sorgente di un software per controllarne la versione, anche se in realtà si può fare con quasi ogni tipo di file sul computer. +Cos'è il controllo di versione, e perché dovresti usarlo? Il controllo di versione è un sistema che registra, nel tempo, i cambiamenti ad un file o ad una serie di file, così da poter richiamare una specifica versione in un secondo momento. Sebbene gli esempi di questo libro usino i sorgenti di un software per controllarne la versione, qualsiasi file di un computer può essere posto sotto controllo di versione. -Se sei un grafico o un webdesigner e vuoi tenere tutte le versioni di un'immagine o di un layout (e sicuramente lo vorrai fare), un Version Control System (VCS) è una cosa saggia da usare. Ti permette di ripristinare i file ad uno stato precedente, ripristinare l'intero progetto ad uno stato precedente, comparare i cambiamenti nel tempo, vedere chi ha modificato cosa che può aver causato un problema, chi ha introdotto un problema e quando, e altro ancora. Usare un VCS, in generale, significa che se si fanno dei pasticci o si perdono dei file, si possono facilmente ripristinare. In aggiunta, si ottiene tutto questo con un piccolo dispendio di risorse. +Se sei un grafico o un webdesigner e vuoi tenere tutte le versioni di un'immagine o di un layout (e sicuramente lo vorrai fare), sarebbe saggio usare un Sistema per il Controllo di Versione (_Version Control System_ - VCS). Un VCS ti permette di ripristinare i file ad una versione precedente, ripristinare l'intero progetto a uno stato precedente, revisionare le modifiche fatte nel tempo, vedere chi ha cambiato qualcosa che può aver causato un problema, chi ha introdotto un problema e quando, e molto altro ancora. Usare un VCS significa anche che se fai un pasticcio o perdi qualche file, puoi facilmente recuperare la situazione. E ottieni tutto questo con poca fatica. ### Sistema di Controllo di Versione Locale ### -Il metodo di controllo di versione scelto da molte persone è di copiare i file in un'altra directory (magari una directory denominata con la data, se sono furbi). Questo approccio è molto comune perché è molto semplice, ma è anche incredibilmente soggetto ad errori. É facile dimenticarsi la directory in cui ci si trova e accidentalmente scrivere sul file sbagliato o copiare i file che non si intendevano copiare. +Molte persone gestiscono le diverse versioni copiando i file in un'altra directory (magari una directory denominata con la data, se sono furbi). Questo approccio è molto comune perché è molto semplice, ma è anche incredibilmente soggetto ad errori. É facile dimenticare in quale directory sei e modificare il file sbagliato o copiare dei file che non intendevi copiare. -Per far fronte a questo problema, i programmatori svilupparono VCS locali che avevano un semplice database che manteneva tutti i cambiamenti dei file sotto controllo di revisione (vedi Figura 1-1). +Per far fronte a questo problema, i programmatori svilupparono VCS locali che avevano un database semplice che manteneva tutti i cambiamenti dei file sotto controllo di revisione (vedi Figura 1-1). Insert 18333fig0101.png -Figura 1-1. Diagramma di controllo di versione locale. +Figura 1-1. Diagramma di controllo di un sistema locale. -Uno dei più popolari strumenti VCS era un sistema chiamato rcs, che è ancora oggi distribuito con alcuni computer. Anche il popolare sistema operativo Mac OS X include il comando rcs quando si installano gli Strumenti di Sviluppo. Semplicemente questo strumento funziona mantenendo una serie di patch (che sono le differenze fra i file) da un cambiamento ad un altro in un formato specifico sul disco; esso può poi ricreare qualsiasi file come se fosse quel file in un determinato momento aggiungendo tutte le patch. +Uno dei più popolari strumenti VCS era un sistema chiamato rcs, che è ancora oggi distribuito con molti computer. Anche il popolare sistema operativo Mac OS X include il comando rcs quando si installano gli Strumenti di Sviluppo. Questo strumento funziona salvando sul disco una serie di patch (ovvero le differenze tra i file) tra una versione e l'altra, in un formato specifico; può quindi ricreare lo stato di qualsiasi file in qualsiasi momento determinato momento, aggiungendo le varie patch. ### Sistemi di Controllo di Versione Centralizzati ### -Il problema successivo in cui incorsero le persone è che queste hanno bisogno di collaborare con altri sviluppatori su altri sistemi. Per far fronte a questo problema, vennero sviluppati sistemi di controllo di versione centralizzati (Centralized Version Control Systems, CVCS). Questi sistemi, come CVS, Subversion e Perforce, hanno un singolo server che contiene tutte le versioni dei file e un numero di utenti che controllano i file dalla centrale. Per alcuni anni, questo fu lo standard per il controllo di versione (vedi Figura 1-2). +Successivamente queste persone dovettero affrontare il problema del collaborare con altri sviluppatori su altri sistemi. Per far fronte a questo problema, vennero sviluppati sistemi di controllo di versione centralizzati (_Centralized Version Control Systems_ - CVCS). Questi sistemi, come CVS, Subversion e Perforce, hanno un unico server che contiene tutte le versioni dei file e un numero di utenti che scaricano i file dal server centrale. Questo è stato lo standard del controllo di versione per molti anni (vedi Figura 1-2). Insert 18333fig0102.png Figura 1-2. Diagramma controllo di versione centralizzato. -Questa impostazione offre molti vantaggi, specialmente rispetto ai VCS locali. Per esempio, chiunque sa, ad un certo livello, cosa stia facendo un'altra persona nel progetto. Gli amministratori hanno un controllo preciso su chi può fare cosa; ed è molto più facile amministrare un tale CVCS che un database locale su ogni client. +Questa impostazione offre molti vantaggi, specialmente rispetto ai VCS locali. Per esempio, chiunque sa, con una certa approssimazione, cosa stia facendo un'altra persona del progetto. Gli amministratori hanno un controllo preciso su chi può fare cosa, ed è molto più facile amministrare un CVCS che un database locale su ogni client. -Tuttavia, questa configurazione ha alcuni gravi lati negativi. La più ovvia è il singolo punto di fallimento che il server centralizzato rappresenta. Se questo va giù per un'ora, durante questo periodo nessuno può collaborare o salvare le modifiche di versione di qualsiasi cosa su cui sta lavorando. Se il disco rigido del database centrale si danneggia, e non sono state effettuate copie di backup, perdi assolutamente tutto - tutta la storia del progetto, ad eccezione di singoli snapshot (istantanee) fatte dalle persone sulla loro macchina locale. Anche i sistemi locali di VCS soffrono di questo problema - ogni volta che si ha tutta la storia del progetto in un unico posto, si rischia di perdere tutto. +Questa configurazione ha tuttavia alcune gravi controindicazioni. La più ovvia è che il server centralizzato rappresenta il singolo punto di rottura del sistema. Se questo va giù per un'ora, in quel periodo nessuno può collaborare o salvare una nuova versione di qualsiasi cosa su cui sta lavorando. Se il disco rigido del database centrale si danneggia, e non ci sono i backup, perdi assolutamente tutto: tutta la storia del progetto ad eccezione dei singoli snapshot (istantanee) che le persone possono avere in locale sulle loro macchine. Anche i sistemi locali di VCS soffrono di questo problema: ogni volta che tutta la storia del progetto è in un unico posto, si rischia di perdere tutto. ### Sistemi di Controllo di Versione Distribuiti ### -E qui entrano in gioco i Sistemi di Controllo di Versione Distribuiti (Distributed Version Control Systems o DVCS). In un DVCS (come Git, Mercurial, Bazaar o Darcs), i client non solo controllano il recente snapshot dei file: essi fanno una copia completa del repository. In tal modo, se si blocca un server ed i sistemi interagiscono tramite un DVCS, un qualsiasi repository di client può essere copiato sul server e quindi ripristinarlo. Ogni checkout, in realtà, è un backup completo di tutti i dati (vedi Figura 1-3). +E qui entrano in gioco i Sistemi di Controllo di Versione Distribuiti (_Distributed Version Control Systems_ - DVCS). In un DVCS (come Git, Mercurial, Bazaar o Darcs), i client non solo controllano lo _snapshot_ più recente dei file, ma fanno una copia completa del repository. In questo modo se un server morisse e i sistemi interagiscono tramite il DVCS, il repository di un qualsiasi client può essere copiato sul server per ripristinarlo. Ogni checkout è un backup completo di tutti i dati (vedi Figura 1-3). Insert 18333fig0103.png -Figura 1-3. Diagramma controllo di versione distribuito. +Figura 1-3. Diagramma del controllo di versione distribuito. Inoltre, molti di questi sistemi trattano bene l'avere più repository remoti su cui poter lavorare, così puoi collaborare con gruppi differenti di persone in modi differenti, simultaneamente sullo stesso progetto. Questo ti permette di impostare diversi tipi di flussi di lavoro che non sono possibili in sistemi centralizzati, come i modelli gerarchici. ## Una Breve Storia di Git ## -Come per molte grandi cose nella vita, Git è iniziato con un po' di distruzione creativa e polemiche di fuoco. Il kernel di Linux è un progetto software open source di portata abbastanza ampia. Per la manutenzione del kernel Linux, per diverso tempo (1991-2002), le modifiche al software venivano passate sotto forma di patch e file d'archivio. Nel 2002, il progetto del kernel di Linux iniziò ad utilizzare un sistema proprietario chiamato DVCS BitKeeper. +Come per molte grandi cose della vita, Git è nato con un po' di distruzione creativa e polemiche infuocate. Il kernel di Linux è un progetto software open source di grande portata. Per buona parte del tempo (1991-2002) della manutenzione del kernel Linux le modifiche al software venivano passate sotto forma di patch e file compressi. Nel 2002, il progetto del kernel Linux iniziò ad utilizzare un sistema DVCS proprietario chiamato BitKeeper. -Nel 2005, il rapporto tra la comunità che ha sviluppato il kernel Linux e la società commerciale che ha sviluppato BitKeeper si ruppe, e l'uso gratuito di questo strumento fu revocato. Ciò ha indotto la comunità di sviluppo di Linux (e in particolare Linus Torvalds, il creatore di Linux) a sviluppare il proprio strumento, basandosi su alcune delle lezioni apprese durante l'utilizzo di BitKeeper. Alcuni degli obiettivi del nuovo sistema sono i seguenti: +Nel 2005 il rapporto tra la comunità che sviluppa il kernel Linux e la società commerciale che aveva sviluppato BitKeeper si ruppe, e fu revocato l'uso gratuito di BitKeeper. Ciò indusse la comunità di sviluppo di Linux (e in particolare Linus Torvalds, il creatore di Linux) a sviluppare uno strumento proprio, basandosi su alcune delle lezioni apprese durante l'utilizzo di BitKeeper. Alcuni degli obiettivi del nuovo sistema erano i seguenti: * Velocità * Design semplice -* Forte supporto allo sviluppo non-lineare (migliaia di rami paralleli) +* Ottimo supporto allo sviluppo non-lineare (migliaia di rami paralleli) * Completamente distribuito * Capacità di gestire, in modo efficiente (velocità e dimensione dei dati), grandi progetti come il kernel Linux -Fin dalla sua nascita nel 2005, Git si è evoluto e maturato per essere facile da usare e tuttora mantiene le sue qualità iniziali. E' incredibilmente veloce, è molto efficiente con grandi progetti, ed ha un incredibile sistema di ramificazioni, per lo sviluppo non lineare (Vedi Capitolo 3). +Fin dalla sua nascita nel 2005 Git si è evoluto e maturato per essere facile da usare e tuttora mantiene le sue qualità iniziali. È incredibilmente veloce, è molto efficiente con progetti grandi e ha un incredibile sistema di ramificazioni, per lo sviluppo non lineare (Vedi Capitolo 3). ## Basi di Git ## -Quindi, cos'è Git in poche parole? Questa è una sezione importante da assorbire, perché se comprendi che cosa è Git e gli elementi fondamentali di come funziona, allora probabilmente, sarà molto più facile per te usare Git efficacemente. Mentre impari Git, cerca di liberare la mente dalle cose che eventualmente conosci su altri VCS, come Subversion e Perforce; ciò ti aiuterà ad evitare di far confusione utilizzando lo strumento. Git immagazzina e tratta le informazioni in modo diverso dagli altri sistemi, anche se l'interfaccia utente è abbastanza simile; comprendere queste differenze aiuta a prevenire di sentirsi confusi, mentre lo si usa. +Quindi, cos'è Git in poche parole? Questa è una sezione importante da comprendere, perché se capisci che cos'è Git e gli elementi fondamentali di come funziona, allora sarà probabilmente molto più facile per te usare efficacemente Git. Mentre impari Git, cerca di liberare la tua mente dalle cose che eventualmente già conosci di altri VCS come Subversion e Perforce; ciò ti aiuterà a evitare di far confusione utilizzando lo strumento. Git immagazzina e tratta le informazioni in modo molto diverso dagli altri sistemi, anche se l'interfaccia utente è abbastanza simile; comprendere queste differenze aiuta a prevenire di sentirsi confusi mentre lo si usa. ### Istantanee, non Differenze ### -La principale differenza tra Git e gli altri VCS (Subversion e compagnia), è il modo in cui Git considera i suoi dati. Concettualmente, la maggior parte degli altri sistemi salvano l'informazione come una lista di cambiamenti apportati ai file. Questi sistemi (CVS, Subversion, Perforce, Bazaar e così via), considerano le informazioni che essi mantengono come un insieme di file, con le relative modifiche fatte ai file, nel tempo, come illustrato in Figura 1-4. +La principale differenza tra Git e gli altri VCS (inclusi Subversion e compagni), è come Git considera i suoi dati. Concettualmente la maggior parte degli altri sistemi salvano l'informazione come una lista di modifiche ai file. Questi sistemi (CVS, Subversion, Perforce, Bazaar e così via), considerano le informazioni che mantengono come un insieme di file, con le relative modifiche fatte ai file nel tempo, come illustrato in Figura 1-4. Insert 18333fig0104.png Figura 1-4. Gli altri sistemi tendono ad immagazzinare i dati come cambiamenti alla versione base di ogni file. -Git non considera i dati in questo modo né li immagazzina in questo modo. Invece, Git considera i propri dati più come una serie di istantanee (snapshot) di un mini filesystem. Ogni volta che si fa un commit, o si salva lo stato del proprio progetto in Git, esso fondamentalmente fa un'immagine di tutti i file in quel momento, salvando un riferimento allo snapshot. Per essere efficiente, se alcuni file non sono cambiati, Git non li immagazzina nuovamente — semplicemente crea un collegamento agli stessi file, già immagazzinati, della versione precedente. Git considera i propri dati più come in Figura 1-5. +Git non considera i dati né li registra in questo modo. Git considera i propri dati più come una serie di istantanee (_snapshot_) di un mini filesystem. Ogni volta che committi, o salvi lo stato del tuo progetto in Git, fondamentalmente lui fa un'immagine di tutti i file in quel momento, salvando un riferimento allo _snapshot_. Per essere efficiente, se alcuni file non sono cambiati, Git non li risalva, ma crea semplicemente un collegamento al file precedente già salvato. Git considera i propri dati più come in Figura 1-5. Insert 18333fig0105.png Figura 1-5. Git immagazzina i dati come snapshot del progetto nel tempo. -Questa è una distinzione importante tra Git e gli altri VCS. Git riconsidera tutti gli aspetti del controllo di versione mentre la maggior parte degli altri sistemi copiano dalle precedenti generazioni. Questo fa di Git più un qualche cosa di simile ad un mini filesystem con alcuni incredibili e potenti strumenti costruiti su di esso, invece che un semplice VCS. Esploreremo alcuni benefici che potrai avere immaginando i tuoi dati in questo modo quando vedremo le ramificazioni con Git nel Capitolo 3. +Questa è una distinzione importante tra Git e pressocché tutti gli altri VCS. Git riconsidera quasi tutti gli aspetti del controllo di versione che la maggior parte degli altri sistemi ha copiato dalle generazioni precedenti. Questo rende Git più simile a un mini filesystem con a disposizione strumenti incredibilmente potenti che un semplice VCS. Esploreremo alcuni benefici che ottieni pensando in questo modo ai tuoi dati e vedremo le ramificazioni (i _branch_) in Git nel Capitolo 3. ### Quasi Tutte le Operazioni Sono Locali ### -La maggior parte delle operazioni in Git, necessitano solo di file e risorse locali per operare — generalmente non occorrono informazioni da altri computer nella rete. Se eri abituato ad un CVCS, in cui la maggior parte delle operazioni erano soggette alle latenze di rete, questo aspetto di Git ti farà pensare che gli dei della velocità abbiano benedetto Git con poteri soprannaturali. Giacché l'intera storia del progetto sta qui, sul proprio disco locale, le operazioni sembrano quasi istantanee. +La maggior parte delle operazioni in Git, necessitano solo di file e risorse locali per operare — generalmente non occorrono informazioni da altri computer della rete. Se sei abituato ad un CVCS in cui la maggior parte delle operazioni sono soggette alle latenze di rete, questo aspetto di Git ti farà pensare che gli Dei della velocità abbiano benedetto Git con poteri soprannaturali. Poiché hai l'intera storia del progetto sul tuo disco locale, molte operazioni sembrano quasi istantanee. -Per esempio, per scorrere la storia di un progetto, Git non ha bisogno di connettersi al server per scaricarla e per poi visualizzarla — la legge direttamente dal database locale. Questo significa che puoi vedere la storia del progetto quasi istantaneamente. Se vuoi vedere i cambiamenti introdotti tra la versione corrente di un file e la versione di un mese fa, Git può consultare il file di un mese fa e calcolare localmente le differenze, invece di richiedere di farlo ad un server remoto o di estrarre una precedente versione del file dal server remoto, per poi farlo in locale. +Per esempio, per navigare la storia di un progetto, Git non ha bisogno di connettersi al server per scaricarla e per poi mostrarla: la legge direttamente dal tuo database locale. Questo significa che puoi vedere la storia del progetto quasi istantaneamente. Se vuoi vedere le modifiche introdotte tra la versione corrente e la versione di un mese fa di un file, Git può accedere al file com'era un mese fa e calcolare le differenze localmente, invece di dover chiedere a un server remoto di farlo o di scaricare dal server remoto una versione precedente del file, per poi farlo in locale. -Questo significa anche che sono minime le cose che non si possono fare se si è offline o non connesso alla VPN. Se sei in aereo o sul treno e vuoi fare un po' di lavoro, puoi eseguire tranquillamente il commit, anche se non sei connesso alla rete per fare l'upload. Se tornando a casa, trovi che il tuo client VPN non funziona correttamente, puoi comunque lavorare. In molti altri sistemi, fare questo è quasi impossibile o penoso. Con Perforce, per esempio, puoi fare ben poco se non sei connesso al server; e con Subversion e CVS, puoi modificare i file, ma non puoi inviare i cambiamenti al tuo database (perché il database è offline). Tutto ciò non ti può sembrare una gran cosa, tuttavia potresti rimanere di stucco dalla differenza che Git può fare. +Questo significa anche che sono pochissime le cose che non puoi fare se sei offline o non sei connesso alla VPN. Se sei in aereo o sul treno e vuoi fare un po' di lavoro, puoi committare tranquillamente in attesa di essere di nuovo connesso per fare l'upload. Se vai a casa e il tuo client VPN non funziona correttamente, puoi lavorare ugualmente. In molti altri sistemi questo è impossibile o molto penoso. Con Perforce, per esempio, puoi fare ben poco se non sei connesso al server; e con Subversion e CVS, puoi modificare i file, ma non puoi inviare le modifiche al tuo database (perché il database è offline). Tutto ciò potrebbe non sembrarti una gran cosa, ma potrebbe sorprenderti quanta differenza possa fare. ### Git Ha Integrità ### -Qualsiasi cosa in Git è controllata, tramite checksum, prima di essere salvata ed è referenziata da un checksum. Questo significa che è impossibile cambiare il contenuto di qualsiasi file o directory senza che Git lo sappia. Questa è una funzionalità interna di Git al più basso livello ed è intrinseco nella sua filosofia. Non puoi perdere informazioni nel transito o avere corruzioni di file senza che Git non sia in grado di accorgersene. +Qualsiasi cosa in Git è controllata, tramite checksum, prima di essere salvata ed è referenziata da un checksum. Questo significa che è impossibile cambiare il contenuto di qualsiasi file o directory senza che Git lo sappia. Questa è una funzionalità interna di basso livello di Git ed è intrinseco della sua filosofia. Non può capitare che delle informazioni in transito si perdano o che un file si corrompa senza che Git non sia in grado di accorgersene. -Il meccanismo che Git usa per fare questo checksum, è un hash, denominato SHA-1. Si tratta di una stringa di 40-caratteri, composta da caratteri esadecimali (0–9 ed a–f) e calcolata in base al contenuto di file o della struttura della directory in Git. Un hash SHA-1 assomiglia a qualcosa come: +Il meccanismo che Git usa per fare questo checksum è un hash chiamato SHA-1. Si tratta di una stringa di 40-caratteri, composta da caratteri esadecimali (0–9 ed a–f) e calcolata in base al contenuto di file o della struttura della directory in Git. Un hash SHA-1 assomiglia a qualcosa come: 24b9da6552252987aa493b52f8696cd6d3b00373 -in Git, questi valori di hash si vedono dappertutto, perché Git li usa tantissimo. Infatti, Git immagazzina ogni cosa, nel proprio database indirizzabile, non per nome di file, ma per il valore di hash del suo contenuto. +Vedrai questi hash dappertutto in Git perché li usa tantissimo. Infatti Git salva qualsiasi cosa nel suo database, e il riferimento ad un file non è basato sul nome del file, ma sull'hash del suo contenuto. ### Git Generalmente Aggiunge Solo Dati ### -Quando si fanno delle azioni in Git, quasi tutte aggiungono solo dati al database di Git. E' piuttosto difficile che si porti il sistema a fare qualcosa che non sia annullabile o a cancellare i dati in una qualche maniera. Come in altri VCS, si possono perdere o confondere le modifiche, di cui non si è ancora fatto il commit; ma dopo aver fatto il commit di uno snapshot in Git, è veramente difficile perderle, specialmente se si esegue regolarmente, il push del proprio database su di un altro repository. +Quasi tutte le azioni in Git aggiungono dati al database di Git. È piuttosto difficile fare qualcosa che non sia annullabile o che cancelli i dati in una qualche maniera. Come negli altri VCS, puoi perdere o fare confusione con le modifiche che non hai ancora committato, ma dopo aver committato uno snapshot in Git, è veramente difficile perderle, specialmente se regolarmente fai il push del tuo database su un altro repository. -Questo rende l'uso di Git un piacere perché sappiamo che possiamo sperimentare senza il pericolo di perdere seriamente le cose. Per un maggior approfondimento su come Git salva i dati e come puoi recuperare i dati che sembrano persi, vedi "Sotto il Cofano" nel Capitolo 9. +Questo rende piaceole l'uso di Git perché sappiamo che possiamo sperimentare senza il pericolo di causare danni pesanti. Per un maggior approfondimento su come Git salvi i dati e come tu possa recuperare quelli che sembrino persi, consulta il Capitolo 9. ### I Tre Stati ### -Ora, presta attenzione. Questa è la prima cosa da ricordare su Git se si vuole affrontare al meglio il processo di apprendimento. Git ha tre stati principali, in cui possono risiedere i file: committed, modified e staged. Committed significa che il file è immagazzinato al sicuro, nel database locale. Modified significa che il file è stato modificato, ma non è stato ancora eseguito il commit nel proprio database. Staged significa che un file modificato nella versione corrente, è stato contrassegnato per essere inserito nello snapshot, al commit successivo. +Ora, presta attenzione. La prima cosa da ricordare sempre di Git se vuoi affrontare al meglio il processo di apprendimento è che i tuoi file in Git possono essere in tre stati: _committed_ (committati), _modified_ (modificati) e _staged_ (in stage). Committato significa che il file è al sicuro nel database locale. Modificato significa che il file è stato modificato, ma non è ancora stato committato nel database. In stage significa che hai contrassegnato un file, modificato nella versione corrente, perché venga inserito nello snapshot alla prossima commit. -Questo ci conduce alle tre sezioni principali di un progetto Git: la directory di Git, la directory di lavoro e l'area di stage. +Questo ci porta alle tre sezioni principali di un progetto Git: la directory di Git, la directory di lavoro e l'area di stage. Insert 18333fig0106.png Figura 1-6. Directory di lavoro, area di stage e directory di Git. -La directory di Git è il luogo dove Git salva i metadati ed il database degli oggetti di un progetto. Questa è la parte più importante di Git, ed è ciò che viene copiato quando si clona un repository da un altro computer. +La directory di Git è dove Git salva i metadati e il database degli oggetti del tuo progetto. Questa è la parte più importante di Git, ed è ciò che viene copiato quando si clona un repository da un altro computer. -La directory di lavoro è un singolo checkout di una versione del progetto. Questi file sono estratti dal database compresso, nella directory di Git, e posizionati nel disco per essere usati o modificati. +La directory di lavoro è un checkout di una versione specifica del progetto. Questi file vengono estratti dal database compresso nella directory di Git, e salvati sul disco per essere usati o modificati. -L'area di stage è un semplice file, generalmente contenuto nella directory di Git, contenente le informazioni riguardanti il commit successivo. Qualche volta viene indicato come l'indice, ma sta diventando d'uso comune riferirsi ad essa, come all'area di stage (sosta, ndt). +L'area di stage è un file, contenuto generalmente nella directory di Git, con tutte le informazioni riguardanti la tua prossima commit. A volte viene indicato anche come 'indice', ma lo standard è definirlo come 'area di stage' (area di sosta, ndt). -Il flusso base di lavoro in Git, funziona come segue: +Il flusso di lavoro (_workflow_) di base in Git funziona così: -1. Modifica i file nella directory di lavoro -2. Esegui l'operazione di stage dei file, per aggiungere i relativi snapshot all'area di stage -3. Esegui il commit, per immagazzinare permanentemente nella directory di Git, lo snapshot relativo, una volta presi i file nell'area di stage +1. Modifica i file nella tua directory di lavoro +2. Fanne lo stage, aggiungendone le istantanee all'area di stage +3. Committa, ovvero salva i file nell'area di stage in un'istantanea (_snapshot_) permanente nella tua directory di Git. -Se una versione particolare di un file è nella directory git, sarà considerata già affidata. Se il file è stato modificato, ma è stato aggiunto all'area di staging, è in sosta. E se è stato modificato da quando è stata controllato, ma non è stato messo in sosta, sarà modificato. Nel Capitolo 2, imparerai di più su questi stati e come trarne vantaggio da essi o saltare interamente la parte di staging. +Se una particolare versione di un file è nella directory git, viene considerata già committata. Se il file è stato modificato, ma è stato aggiunto all'area di staging, è _in stage_. E se è stato modificato da quando è stata estratto, ma non è _in stage_, è modificato. Nel Capitolo 2, imparerai di più su questi stati e come trarne vantaggio o saltare la parte di staging. ## Installare Git ## -Incominciamo ad usare un po' di Git! Per prima cosa — occorre installarlo. Puoi ottenere Git in diversi modi; i due principali sono: installarlo dai sorgenti o installarlo da un pacchetto pre-esistente per la tua piattaforma. +Incominciamo ad usare un po' di Git! Per prima cosa devi installarlo. Puoi ottenere Git in diversi modi; i principali due sono: installarlo dai sorgenti o installarlo da un pacchetto pre-esistente per la tua piattaforma. ### Installare da Sorgenti ### -Se puoi, è generalmente vantaggioso installare Git dai sorgenti, perché così puoi usare la versione più recente. Ogni versione di Git, tende ad includere utili miglioramenti all'interfaccia utente, quindi, avere l'ultima versione disponibile è spesso la scelta migliore, se hai familiarità con la compilazione dei sorgenti. Inoltre capita anche, che molte distribuzioni Linux contengano pacchetti molto vecchi; perciò, se non stai usando una distro aggiornata o dei backport, l'installazione da sorgente può essere la cosa migliore da fare. +Se puoi, generalmente è vantaggioso installare Git dai sorgenti perché avrai la versione più recente. Ogni versione di Git tende ad includere utili miglioramenti all'interfaccia utente e avere quindi l'ultima versione disponibile è spesso la scelta migliore, se hai familiarità con la compilazione dei sorgenti. Inoltre capita anche, che molte distribuzioni Linux usino pacchetti molto vecchi; perciò, se non stai usando una distro aggiornata o dei backport, l'installazione da sorgente può essere la cosa migliore da fare. -Per installare Git, hai bisogno delle seguenti librerie, da cui dipende Git: curl, zlib, openssl, expat e libiconv. Per esempio, se sei su un sistema che usa yum (come in Fedora), o apt-get (come nei sistemi Debian), puoi usare uno dei seguenti comandi per installare tutte le dipendenze: +Per installare Git, hai bisogno delle librerie da cui dipende Git che sono: curl, zlib, openssl, expat e libiconv. Per esempio, se sei su un sistema che usa yum (come Fedora), o apt-get (come nei sistemi Debian), puoi usare uno dei seguenti comandi per installare tutte le dipendenze: $ yum install curl-devel expat-devel gettext-devel \ openssl-devel zlib-devel @@ -140,88 +140,92 @@ Quando avrai tutte le dipendenze necessarie, puoi proseguire ed andare a recuper Poi, compilalo ed installalo: - $ tar -zxf git-1.6.0.5.tar.gz - $ cd git-1.6.0.5 + $ tar -zxf git-1.7.2.2.tar.gz + $ cd git-1.7.2.2 $ make prefix=/usr/local all $ sudo make prefix=/usr/local install -Dopo aver fatto questo, puoi ottenere Git da Git stesso per gli aggiornamenti: +Dopo aver fatto questo, puoi scaricare gli aggiornamenti di Git con lo stesso Git: $ git clone git://git.kernel.org/pub/scm/git/git.git ### Installare su Linux ### -Se vuoi installare Git su Linux, tramite una installazione da binario, generalmente, puoi farlo con lo strumento base di amministrazione-dei-pacchetti della tua distribuzione. Se sei su Fedora, puoi usare yum: +Se vuoi installare Git su Linux, tramite una installazione da binario, generalmente puoi farlo con lo strumento base di amministrazione dei pacchetti della tua distribuzione. Se usi Fedora, puoi usare yum: - $ yum install git-core + $ yum install git -O se sei su una distribuzione basata su Debian, come Ubuntu, prova apt-get: +O, se usi una distribuzione basata su Debian (come Ubuntu) prova apt-get: $ apt-get install git ### Installazione su Mac ### -Ci sono due metodi per installare Git su Mac. Il più semplice è usare l'installatore grafico di Git, che puoi scaricare dalla pagina di Google Code (vedi Figura 1-7): +Ci sono due metodi per installare facilmente Git su Mac. Il più semplice è usare l'installazione l'installer grafico di Git, che puoi scaricare da SourceForge (vedi Figura 1-7): - http://code.google.com/p/git-osx-installer + http://sourceforge.net/projects/git-osx-installer/ Insert 18333fig0107.png -Figura 1-7. Installatore di Git per SO X. +Figura 1-7. Installer di Git per OS X. -L'altro metodo è installare Git via MacPorts (`http://www.macports.org`). Se hai MacPorts installato, installa Git con: +La prima alternativa è usando MacPorts (`http://www.macports.org`). Se hai già installato MacPorts puoi installare Git con: - $ sudo port install git-core +svn +doc +bash_completion +gitweb + $ sudo port install git +svn +doc +bash_completion +gitweb -Non ti occorre aggiungere tutti i pacchetti, ma evidentemente vorrai includere +svn, nel caso tu debba usare Git con i repository di Subversion (vedi Capitolo 8). +Non ti occorre aggiungere tutti i pacchetti extra, ma probabilmente vorrai includere +svn, nel caso tu debba usare Git con i repository di Subversion (vedi Capitolo 8). + +La seconda alternativa è Homebrew (`http://brew.sh/`). Se hai già installato Homebrew puoi installare Git con: + + $ brew install git ### Installare su Windows ### -Installare Git su Windows è davvero facile. Il progetto msysGit ha una delle procedure di installazione tra le più facili. Semplicemente scarica l'installatore eseguibile dalla pagina di GitHub, e lancialo: +Installare Git su Windows è davvero facile. Il progetto msysGit ha una delle procedure di installazione più facili. Semplicemente scarica l'eseguibile dalla pagina di GitHub e lancialo: - http://msysgit.github.com/ + http://msysgit.github.io/ -Una volta installato, hai a disposizione sia la versione da riga di comando (incluso un client SSH che sarà utile, in seguito) sia l'interfaccia grafica (GUI) standard. +Una volta installato avrai a disposizione sia la versione da riga di comando (incluso un client SSH ti servirà in seguito) sia l'interfaccia grafica (_GUI_) standard. -Nota sull'uso su Windows: dovresti usare Git con la shell msysGit fornita (stile Unix), permette di usare complesse linee di comando date in questo libro. Se hai bisogno, per qualche ragione, di usare la shell nativa di Windows / la console a linea di comando, devi usare le doppie virgolette invece delle virgolette semplici (per i parametri con che contengono spazi) e devi virgolettare i parametri che terminano con l'accento circonflesso (^) se questi sono al termine della linea, poiché esso è un simbolo di proseguimento in Windows. +Nota sull'uso su Windows: dovresti usare Git con la shell msysGit fornita (stile Unix) perché permette di usare le complesse linee di comando di questo libro. Se hai bisogno, per qualche ragione, di usare la shell nativa di Windows / la console a linea di comando, devi usare le doppie virgolette invece delle virgolette singole (per i parametri con che contengono spazi) e devi virgolettare i parametri che terminano con l'accento circonflesso (^) se questi sono al termine della linea, poiché in Windows è uno dei simboli di proseguimento. ## Prima Configurazione di Git ## -Ora che hai Git sul tuo sistema, vorrai fare un paio di cose per personalizzare l'ambiente di Git. Ti occorre farle solo una volta; esse rimangono invariate anche dopo un aggiornamento. Comunque, puoi cambiarle, in ogni momento, eseguendo di nuovo questi comandi. +Ora che hai Git sul tuo sistema vorrai fare un paio di cose per personalizzare l'ambiente di Git. Devi farle solo una volta: rimarrano invariate anche dopo un aggiornamento. Puoi comunque cambiarle in ogni momento, rieseguendo i comandi. -Git è rilasciato con uno strumento che si chiama git config che ti permetterà di ottenere ed impostare le variabili di configurazione che controllano ogni aspetto delle operazioni e del look di Git. Queste variabili possono essere salvate in tre posti differenti: +Git viene con uno strumento che si chiama 'git config' che ti permetterà d'impostare e conoscere le variabili di configurazione che controllano ogni aspetto di come appare Git e come opera. Queste variabili possono essere salvate in tre posti differenti: -* file `/etc/gitconfig`: Contiene i valori per ogni utente sul sistema e per tutti i loro repository. Se si passa l'opzione` --system` a `git config`, lui legge e scrive da questo specifico file. -* file `~/.gitconfig`: Specifico per il tuo utente. Puoi far leggere e scrivere a Git questo file passando l'opzione `--global`. -* file di configurazione nella directory git (che è `.git/config`) di ogni repository che si sta usando. Specifico per ogni singolo repository. Ogni livello sovrascrive i valori del livello precedente, così i valori in `.git/config` vincono su quelli in `/etc/gitconfig`. +* `/etc/gitconfig`: Contiene i valori per ogni utente sul sistema e per tutti i loro repository. Se passi l'opzione` --system` a `git config`, lui legge e scrive da questo file specifico. +* `~/.gitconfig`: Specifico per il tuo utente. Puoi far leggere e scrivere a Git questo file passando l'opzione `--global`. +* file di configurazione nella directory git (cioè `.git/config`) di qualsiasi repository che si stia usando. È Specifico di quel singolo repository. Ogni livello sovrascrive i valori del precedente, così che i valori in `.git/config` vincono su quelli in `/etc/gitconfig`. -Sui sistemi Windows, Git cerca il file `.gitconfig` nella directory `$HOME` (`C:\Documents and Settings\$USER` per la maggior parte delle persone). Inoltre per quanto riguarda /etc/gitconfig, sarà relativo alla radice di MSys, che dipende da dove si vorrà installare Git sul sistema Windows quando si lancia l'installazione. +Su Windows Git cerca il file `.gitconfig` nella directory `$HOME` (`%USERPROFILE%` in Windows), che per la maggior parte delle persone è `C:\Documents and Settings\$USER` o `C:\Users\$USER`, dipendendo dalla versione (`$USER` è `%USERNAME%` in Windows). Controlla comunque anche /etc/gitconfig, sebbene sia relativo alla root di MSys, che è dove hai deciso di installare Git in Windows quando si lancia l'installazione. -### La Propria Identità ### +### La tua Identità ### -La prima cosa che occorrerebbe fare, quando si installa Git, è impostare il proprio nome utente e indirizzo e-mail. Ciò è importante, perché ogni commit di Git usa queste informazioni, che vengono incapsulate nei commit che si fanno: +La prima cosa che occorrerebbe fare quando installi Git è impostare il tuo nome utente e il tuo indirizzo e-mail. Questo è importante perché ogni commit di Git usa queste informazioni che vengono incapsulate nelle tue commit: $ git config --global user.name "John Doe" $ git config --global user.email johndoe@example.com -Di nuovo, passando l'opzione `--global`, occorre fare ciò solo una volta, dopo di che Git userà sempre queste informazioni, per qualsiasi operazione fatta sul sistema. Se si vuole sovrascriverle con un nome o una e-mail per progetti specifici, basta eseguire il comando senza l'opzione `--global`, quando si è in uno di quei progetti. +Con l'opzione `--global` dovrai farlo solo una volta, dopo di che Git userà sempre queste informazioni per qualsiasi operazione fatta sul sistema. Se vuoi sovrascriverle con un nome o una e-mail diversi per progetti specifici potrai eseguire il comando senza l'opzione `--global`stando in uno di quei progetti. -### Il Proprio Editor ### +### Il tuo Editor ### -Ora che è configurata la propria identità, si può configurare l'editor di testo predefinito, da usare quando Git avrà bisogno di inserire un messaggio. Per impostazione predefinita, Git usa l'editor di testo predefinito del sistema, che generalmente è Vi o Vim. Se vuoi usare un editor di testo differente, come Emacs, puoi fare come segue: +Ora che hai configurato la tua identità, puoi configurare il tuo editor di testo predefinito, che verrà usato quando Git avrà bisogno che scriva un messaggio. Per impostazione predefinita Git usa l'editor di testo predefinito del sistema, che generalmente è Vi o Vim. Se vuoi usarne uno diverso, come Emacs, potrai eseguire: $ git config --global core.editor emacs -### Il Proprio Diff ### +### Il tuo Diff ### -Un'altra utile opzione, che si potrebbe voler configurare, è lo strumento diff, predefinito, da usare per risolvere i conflitti di merge (fusione, ndt). Per usare vimdiff: +Un'altra opzione utile che potresti voler configurare, è lo strumento diff predefinito, da usare per risolvere i conflitti di _merge_ (unione, ndt). Per usare vimdiff, potrai eseguire: $ git config --global merge.tool vimdiff -Git accetta kdeff3, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, ecmerge e opendiff, come strumenti validi di merge. E' anche possibile impostare uno strumento personalizzato; vedere il Capitolo 7, per maggiori informazioni su come farlo. +Git accetta kdeff3, tkdiff, meld, xxdiff, emerge, vimdiff, gvimdiff, ecmerge e opendiff, come strumenti di merge validi. Puoi anche definire uno personalizzato: vedi il Capitolo 7 per maggiori informazioni su come farlo. -### Controllare le Impostazioni ### +### Controlla le tue impostazioni ### -Per controllare le proprie impostazioni, si può usare il comando `git config --list`, che elenca tutte le impostazioni di Git, fatte fino a questo punto: +Per controllare le tue impostazioni puoi usare il comando `git config --list` che elenca tutte le impostazioni attuali di Git: $ git config --list user.name=Scott Chacon @@ -232,28 +236,28 @@ Per controllare le proprie impostazioni, si può usare il comando `git config -- color.diff=auto ... -La stessa chiave può comparire più volte, perché Git legge la stessa chiave da file differenti (`/etc/gitconfig` e `~/.gitconfig`, per esempio). In questo caso, Git usa l'ultimo valore per ogni chiave unica che vede. +Potresti vedere più volte la stessa chiave perché Git legge la stessa chiave da file differenti (`/etc/gitconfig` e `~/.gitconfig`, per esempio). In questo caso, Git usa l'ultimo valore per ogni chiave unica che trova. -Per controllare quale sia il valore di una chiave, ritenuto da Git usare, `git config {key}`: +Puoi anche controllare quale sia il valore di una chiave specifica digitando `git config {key}`: $ git config user.name Scott Chacon -## Ottenere Aiuto ## +## Ottieni aiuto ## -Se dovessi avere bisogno di aiuto durante l'uso di Git, ci sono tre modi per vedere le pagine del manuale di aiuto per ogni comando di Git: +Se dovessi avere bisogno di aiuto durante l'uso di Git, ci sono tre modi per vedere le pagine del manuale (_manpage_) per ogni comando di Git: $ git help $ git --help $ man git- -Per esempio, puoi avere la pagina del manuale di aiuto, per il comando config, lanciando +Per esempio, puoi consultare la pagina del manuale per il comando config digitanto $ git help config -Questi comandi sono utili, perché puoi accedere ad essi da ogni dove, anche se sei offline. -Se il manuale e questo libro non sono sufficienti e hai bisogno di un aiuto più diretto da una persona, puoi provare i canali `#git` o `#github`, sul server IRC di Freenode (irc.freenode.com). Questi canali sono regolarmente frequentati da centinaia di persone che conoscono molto bene Git e saranno davvero felici di aiutarti. +Questi comandi sono utili perché puoi accedervi dappertutto, anche quando sei offline. +Se il manuale e questo libro non fossero sufficienti e avessi bisogno dell'aiuto di una persona, puoi provare i canali `#git` o `#github` sul server IRC di Freenode (irc.freenode.com). Questi canali sono frequentati regolarmente da centinaia di persone che conoscono molto bene Git e spesso sono disponibili per dare una mano. -## Riassunto ## +## Sommario ## -Dovresti avere le basi per capire cos'è Git e come è differente dai CVCS che puoi aver usato. Dovresti anche avere una versione funzionante di Git sul tuo sistema che è configurata con la tua personale identità. É ora tempo di imparare qualcosa delle basi di Git. +Dovresti avere le basi per capire cos'è Git e com'è diverso dai CVCS che potresti aver usato. Dovresti avere già una versione funzionante di Git sul tuo sistema che è configurata con i tuoi dati. È ora tempo di imparare alcune delle basi di Git. diff --git a/it/02-git-basics/01-chapter2.markdown b/it/02-git-basics/01-chapter2.markdown index 25de9ca5e..c2512d22b 100644 --- a/it/02-git-basics/01-chapter2.markdown +++ b/it/02-git-basics/01-chapter2.markdown @@ -1,180 +1,183 @@ # Basi di Git # -Se puoi leggere solo un capitolo per capire l'uso di Git, questo fa per te. Questo capitolo illustra tutti i comandi base per fare la stragrande maggioranza delle cose impiegando al meglio il tuo tempo con Git. Alla fine del capitolo, dovresti essere in grado di configurare ed inizializzare un repository, avviare e fermare il tracciamento dei file e mettere in stage o eseguire il commit dei cambiamenti. Vedremo come impostare Git per ignorare certi file o pattern di file, come correggere gli errori velocemente e facilmente, come navigare nella storia del tuo progetto e vedere i cambiamenti tra i vari commit e come fare il push ed il pull da repository remoti. +Se puoi leggere un solo capitolo per imparare Git, leggi questo. Questo capitolo illustra tutti i comandi base di cui hai bisogno per la stragrande maggioranza delle cose che farai con Git. Alla fine del capitolo sarai in grado di configurare e creare un repository, iniziare e interrompere il tracciamento dei file e mettere in stage e committare le modifiche. Vedremo come impostare Git per ignorare certi file o pattern, come annullare velocemente e facilmente gli errori, come navigare la cronologia del tuo progetto e vedere le modifiche tra le varie commit e come fare il push ed il pull da repository remoti. -## Ottenere un Repository Git ## +## Repository Git ## -Puoi creare un progetto Git usando due approcci principali. Il primo prende un progetto esistente o una directory e la importa in Git. Il secondo clona un repository Git esistente da un altro server. +Puoi creare un progetto Git principalmente con due approcci. Il primo prende un progetto esistente o una directory e la importa in Git. Il secondo clona un repository Git esistente, su un altro server. -### Inizializzare un Repository in una Directory Esistente ### +### Creare un repository in una directory preesistente ### -Se stai iniziando a tracciare un progetto esistente con Git, devi posizionarti nella directory del progetto e digitare: +Se vuoi iniziare a tenere traccia con Git di un progetto esistente, devi andare nella directory del progetto e digitare: $ git init -Questo creerà una nuova sottodirectory chiamata .git che conterrà tutti i file necessari per il repository — uno scheletro del repository Git. A questo punto, niente del tuo progetto è già tracciato. (Vedi il Capitolo 9 per avere maggiori informazioni esatte sui file che sono contenuti nella directory `.git` che hai appena creato.) +Questo creerà una nuova sottodirectory chiamata `.git` che conterrà tutti i file necessari per il tuo repository, una struttura del repository Git. A questo punto non è ancora stato tracciato niente del tuo progetto. (Vedi il *Capitolo 9* per sapere quali file sono contenuti nella directory `.git` che hai appena creato.) -Se vuoi iniziare a tracciare i file esistenti (al contrario di una directory vuota), dovresti iniziare a monitorare questi file eseguendo un commit iniziale. Lo puoi fare con pochi comandi che specificano quali file vuoi controllare, seguiti da un commit: +Se vuoi iniziare a tracciare i file esistenti (a differenza di una directory vuota), dovresti iniziare a monitorare questi file con una commit iniziale. Lo puoi fare con pochi `git add`, che specificano quali file vuoi tracciare, seguiti da una commit: $ git add *.c $ git add README $ git commit -m 'initial project version' -Vedremo in seguito velocemente cosa fanno questi comandi. A questo punto hai un repository Git con dei file tracciati ed un commit iniziale. +Tra un minuto vedremo cosa fanno questi comandi. A questo punto hai un repository Git con dei file tracciati e una commit iniziale. ### Clonare un Repository Esistente ### -Se vuoi avere la copia di un repository Git esistente — per esempio, un progetto a cui vuoi contribuire — il comando di cui hai bisogno è git clone. Se hai familiarità con altri sistemi VCS come Subversion, noterai che il comando è clone e non checkout. Questa è una distinzione importante — Git riceve una copia di circa tutti i dati che un server possiede. Ogni versione di ogni file della storia del progetto sono scaricate quando lanci `git clone`. Infatti, se il disco del tuo server è corrotto, puoi usare qualsiasi copia di qualsiasi client per ripristinare il server allo stato in cui era quando è stato clonato (puoi perdere alcuni agganci server, ma tutte le versioni dei dati saranno presenti — vedi il Capitolo 4 per maggiori dettagli). +Se vuoi copiare un repository Git esistente — per esempio, un progetto a cui vuoi contribuire — il comando di cui hai bisogno è `git clone`. Se hai familiarità con altri sistemi VCS come Subversion, noterai che il comando è `clone` e non `checkout`. Questa è una distinzione importante: Git riceve una copia di quasi tutti i dati che sono sul server. Quando esegui `git clone` vengono scaricate tutte le versioni di ciascun file della cronologia del progetto. Infatti, se si danneggiasse il disco del tuo server, potresti usare qualsiasi clone di qualsiasi client per ripristinare il server allo stato in cui era quando è stato clonato (potresti perdere alcuni `hooks` lato-server, ma tutte le versioni dei dati saranno presenti: vedi il *Capitolo 4* per maggiori dettagli). -Clona un repository con `git clone [url]`. Per esempio, se vuoi clonare la libreria Ruby Git chiamata Grit, puoi farlo così: +Cloni un repository con `git clone [url]`. Per esempio, se vuoi clonare la libreria Ruby Git chiamata Grit, puoi farlo così: $ git clone git://github.com/schacon/grit.git -Questo comando crea un directory "grit", inizializza una directory `.git` dentro di essa, scarica tutti i dati per questo repository ed imposta la copia di lavoro dell'ultima versione. Se entri nella nuova directory `grit`, vedrai i file del progetto, pronti per essere modificati o usati. Se vuoi clonare il repository in una directory con un nome diverso da grit, puoi specificarlo come opzione successiva al comando da terminale: +Questo comando crea un directory "grit", dentro di questa inizializza una directory `.git`, scarica tutti i dati del repository e fa il checkout dell'ultima versione per poterci lavorare su. Se vai nella nuova directory `grit`, vedrai i file del progetto, pronti per essere modificati o usati. Se vuoi clonare il repository in una directory con un nome diverso da grit, puoi specificarlo sulla riga di comando: $ git clone git://github.com/schacon/grit.git mygrit -Questo comando fa la stessa cosa del precedente, ma la directory di destinazione è chiamata mygrit. +Questo comando fa la stessa cosa del precedente, ma la directory di destinazione è chiamata `mygrit`. -Git può usare differenti protocolli di trasferimento. L'esempio precedente usa il protocollo `git://`, ma puoi anche vedere `http(s)://` o `user@server:/path.git`, che usa il protocollo di trasferimento SSH. Il Capitolo 4 introdurrà tutte le opzioni disponibili che il server può impostare per farti accedere al repository Git ed i pro e i contro di ognuna. +Git può usare differenti protocolli di trasferimento. L'esempio precedente usa il protocollo `git://`, ma puoi anche vedere `http(s)://` o `user@server:/path.git`, che usa il protocollo di trasferimento SSH. Il *Capitolo 4* introdurrà tutte le opzioni che un server può rendere disponibili per l'accesso al repository Git e i pro e i contro di ciascuna. -## Registrare i Cambiamenti nel Repository ## +## Salvare le modifiche sul repository ## -In buona fede hai copiato un repository Git e hai la copia di lavoro dei file di questo progetto. Ora puoi apportare alcune modifiche ed inviare gli snapshots di questi cambiamenti nel tuo repository ogni volta che il progetto raggiunge uno stato che vuoi registrare. +Hai clonato un vero repository Git e hai la copia di lavoro dei file del progetto. Ora puoi fare qualche modifica e inviare gli snapshots di queste al tuo repository ogni volta che il progetto raggiunga uno stato che vuoi salvare. -Ricorda che ogni file nella tua directory di lavoro è in una dei due stati seguenti: *tracciato* o *non tracciato*. I file *tracciati* sono i file presenti nell'ultimo snapshot; possono essere *non modificati*, *modificati* o *staged* (parcheggiati, ndt). I file *non tracciati* sono tutti gli altri - qualsiasi file nella tua directory di lavoro che non è presente nel tuo ultimo snapshot o nella tua area di stage. Quando cloni per la prima volta un repository, tutti i tuoi file sono tracciati e non modificati perché li hai appena prelevati e non hai modificato ancora niente. +Ricorda che ogni file della tua directory di lavoro può essere in uno dei due stati seguenti: *tracked* (tracciato, ndt.) o *untracked* (non tracciato, ndt.). I file *tracked* sono già presenti nell'ultimo snapshot; possono quindi essere *unmodified* (non modificati, ndt.), *modified* (modificati, ndt.) o *staged*. I file *untracked* sono tutti gli altri: qualsiasi file nella tua directory di lavoro che non è presente nell'ultimo snapshot o nella tua area di stage. Quando cloni per la prima volta un repository, tutti i tuoi file sono tracciati e non modificati perché li hai appena prelevati e non hai modificato ancora niente. -Quando modifichi i file, Git li vede come cambiati, perché li hai modificati rispetto all'ultimo commit. Parcheggi questi file e poi esegui il commit di tutti i cambiamenti presenti nell'area di stage, ed il ciclo si ripete. Questo ciclo di vita è illustrato nella Figura 2-1. +Quando editi dei file, Git li vede come modificati, perché sono cambiati rispetto all'ultima commit. Metti nell'area di stage i file modificati e poi fai la commit di tutto ciò che è in quest'area, e quindi il ciclo si ripete. Questo ciclo di vita è illustrato nella Figura 2-1. Insert 18333fig0201.png Figura 2-1. Il ciclo di vita dello stato dei tuoi file. -### Controlla lo Stato dei Tuoi File ### +### Controlla lo stato dei tuoi file ### -Lo strumento principale che userai per determinare quali file sono in un certo stato è il comando git status. Se lanci questo comando direttamente dopo aver fatto una clonazione, dovresti vedere qualcosa di simile a: +Lo strumento principale che userai per determinare lo stato dei tuoi file è il comando `git status`. Se esegui questo comando appena dopo un clone, dovresti vedere qualcosa di simile: $ git status # On branch master - nothing to commit (working directory clean) + nothing to commit, working directory clean -Questo significa che hai una directory di lavoro pulita — in altre parole, non c'è traccia di file modificati. Git inoltre non vede altri file non tracciati, altrimenti sarebbero elencati qui. Infine, il comando ci dice in quale ramo si è. Per ora, è sempre il master, che è il predefinito; non preoccuparti di questo per ora. Il prossimo capitolo tratterà delle ramificazioni e dei riferimenti nei dettagli. +Questo significa che hai una directory di lavoro pulita, ovvero che nessuno dei file tracciati è stato modificato. Inoltre Git non ha trovato nessun file non ancora tracciato, altrimenti sarebbero elencati qui. In aggiunta il comando indica anche in quale ramo sei. Per ora, è sempre `master`, che è il predefinito; non preoccupartene per ora. Il prossimo capitolo tratterà in dettagli dei `branch` (ramificazioni) e dei riferimenti. -Ora diciamo che hai aggiunto un nuovo file al tuo progetto, un semplice file README. Se il file non esisteva prima, e lanci `git status`, vedrai il tuo file non tracciato come segue: +Immagina di aver aggiunto un nuovo file al tuo progetto, un semplice README. Se il file non esisteva e lanci `git status`, vedrai così il file non tracciato: $ vim README $ git status - # On branch master - # Untracked files: - # (use "git add ..." to include in what will be committed) - # - # README + On branch master + Untracked files: + (use "git add ..." to include in what will be committed) + + README + nothing added to commit but untracked files present (use "git add" to track) -Puoi vedere che il tuo nuovo file README non è tracciato, perché è sotto al titolo "Untracked files" nell'output degli stati. Untracked fondamentalmente significa che Git vede un file che non avevi nel precedente snapshot (commit); Git non inizierà ad includerlo negli snapshot dei tuoi commit fino a quando tu non glielo dirai esplicitamente. Si comporta così per evitare che tu accidentalmente includa file binari generati o qualsiasi altro tipo di file che non vuoi sia incluso. Se vuoi includere il file README, continua con il tracciamento dei file. +Puoi vedere che il nuovo file README non è tracciato poiché nell'output è nella sezione dal titolo "Untracked files". `Untracked` significa che Git vede un file che non avevi nello `snapshot` precedente (commit); Git non lo includerà negli snapshot delle tuoe commit fino a quando non glielo dirai esplicitamente. Fa così per evitare che includa accidentalmente dei file binari generati o qualsiasi altro tipo di file che non intendi includere. Se vuoi includere il README, iniziamo a tracciarlo. ### Tracciare Nuovi File ### -Per iniziare a tracciare un nuovo file, usa il comando `git add`. Per tracciare il file `README`, lancia questo comando: +Per iniziare a tracciare un nuovo file, si usa il comando `git add`. Per tracciare il file `README`, usa questo comando: $ git add README -Se lanci nuovamente il comando di stato, puoi vedere il tuo file `README` tracciato e parcheggiato: +Se lanci nuovamente il comando per lo stato, puoi vedere che il tuo file `README` ora è tracciato e nell'area di `stage`: $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README + -Ti dice che è in stage (parcheggiato, ndt) perché è sotto al titolo "Changes to be committed". Se fai ora il commit, la versione del file al momento in cui hai lanciato `git add` sarà quella che troverai nella storia dello snapshot. Potresti ricordare che quando hai eseguito `git init` precedentemente, poi hai dovuto lanciare `git add (file)` — che era necessario per l'inizio del tracciamento dei file nella tua directory. Il comando git add prende il nome del percorso di ogni file o directory; se è una directory, il comando aggiunge tutti i file in quella directory ricorsivamente. +Sai che è nell'area di `stage` perché è nella sezione "Changes to be committed". Se a questo punto fai commit, la versione del file com'era quando hai lanciato `git add` sarà quella che troverai nella cronologia dello snapshot. Ricorderai che quando prima hai eseguito `git init`, poi hai dovuto lanciare `git add (file)`, che era necessario per iniziare a tracciare i file nella tua directory. Il comando `git add` accetta il nome del percorso di un file o una directory; se è una directory, il comando aggiunge ricorsivamente tutti i file in quella directory. -### Parcheggiare File Modificati ### +### Fare lo stage dei file modificati ### -Ora modifichiamo un file che è già stato tracciato. Se modifichi un file precedentemente tracciato chiamato `benchmarks.rb` e poi avvii nuovamente il comando `status`, otterrai qualcosa di simile a: +Modifichiamo un file che è già tracciato. Se modifichi un file tracciato chiamato `benchmarks.rb` e poi esegui il comando `status`, otterrai qualcosa di simile a: $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README -Il file benchmarks.rb appare sotto la sezione chiamata "Changes not staged for commit" — che significa che un file che è tracciato è stato modificato nella directory di lavoro ma non ancora messo in stage. Per parcheggiarlo, avvia il comando `git add` (è un comando multifunzione — è usato per iniziare a tracciare nuovi file, per parcheggiare i file e per fare altre cose come eseguire la fusione dei file che entrano in conflitto dopo che sono stati risolti). Avvia dunque `git add` per parcheggiare ora il file benchmarks.rb, e avvia nuovamente `git status`: + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + + +Il file benchmarks.rb appare nella sezione chiamata "Changes not staged for commit" — che significa che un file tracciato è stato modificato nella directory di lavoro ma non è ancora nello stage. Per farlo, esegui il comando `git add` (è un comando multifunzione — lo usi per iniziare a tracciare nuovi file, per fare lo stage dei file e per fare altre cose, ad esempio per segnare come risolti i conflitti causati da un `merge`). Esegui `git add` per mettere in `stage` il file benchmarks.rb, e riesegui `git status`: $ git add benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README + modified: benchmarks.rb + -Entrambi i file sono parcheggiati ed entreranno nel prossimo commit. A questo punto, supponendo che tu ti sia ricordato di una piccola modifica da fare a benchmarks.rb prima di fare il commit. Apri nuovamente il file ed esegui la modifica, e ora sei pronto per il commit. Come sempre, lanci `git status` ancora una volta: +Entrambi i file sono nello `stage` e staranno nella prossima commit. A questo punto, immagina che ti sia ricordato di una piccola modifica da fare in 'benchmarks.rb' prima della commit. Riapri il file e fai la modifica: ora sei pronto per la commit. Come sempre, esegui `git status` di nuovo: $ vim benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # modified: benchmarks.rb - # - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # - # modified: benchmarks.rb - # - -Che succede? Ora benchmarks.rb è elencato sia in stage che non. Come è possibile? É saltato fuori che Git ha parcheggiato il file esattamente come se tu avessi avviato il comando git add. Se esegui ora il commit, la versione di benchmarks.rb che verrà inviata nel commit sarà quella di quando tu hai lanciato il comando git add, non la versione del file che appare nella tua directory di lavoro quando lanci git commit. Se modifichi un file dopo che hai lanciato `git add`, devi nuovamente avviare `git add` per parcheggiare l'ultima versione del file: + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README + modified: benchmarks.rb + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + + +Cos'è successo? Ora `benchmarks.rb` è elencato sia dentro che fuori lo `stage`. Come è possibile? È saltato fuori che Git ha messo in `stage` il file esattamente com'era quando hai eseguito `git add`. Se committi ora, la versione di `benchmarks.rb` che verrà committata sarà quella che avevi quando hai eseguito il `git add`, non la versione del file che trovi nella directory di lavoro quando esegui `git commit`. Se modifichi un file dopo che hai eseguito `git add`, devi rieseguire `git add` per mettere nello `stage` l'ultima versione del file: $ git add benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README + modified: benchmarks.rb + ### Ignorare File ### -Spesso, si ha una classe di file che non si vuole automaticamente aggiungere o far vedere come file non tracciati a Git. Ci sono generalmente alcuni file generati automaticamente come i file di log o i file prodotti dalla creazione di un sistema. In questi casi, puoi creare un file chiamato .gitignore con una lista di pattern corrispondente ad essi. Questo è un esempio di file .gitignore: +Spesso hai dei file che non vuoi che Git aggiunga automaticamente e nemmeno che te li mostri come tracciati. Generalmente si tratta di file generati automaticamente, come i log o quelli prodotti dal tuoi sistema di `build`. In questi casi puoi creare un file chiamato `.gitignore` con la lista di pattern dei file che vuoi ignorare. Questo è un `.gitignore` d'esempio: $ cat .gitignore *.[oa] *~ -La prima linea dice a Git di ignorare qualsiasi file che finisce con .o o .a — file di oggetti o archivi che possono essere il prodotto di una compilazione del tuo codice. La seconda linea dice a Git di ignorare tutti i file che finiscono con la tilde (`~`), che è usata da alcuni editor di testo come Emacs per marcare i file temporanei. Puoi anche includere directory di log, tmp o pid; documentazioni generate automaticamente; e così via. Imposta un file .gitignore prima di di procedere è generalmente una buona idea, così si evita il rischio di eseguire accidentalmente dei commit dei file che non vuoi nel tuo repository Git. +La prima riga dice a Git di ignorare qualsiasi file che finisce in `.o` o `.a` — file di oggetti o archivi che possono essere il prodotto di una compilazione del tuo codice. La seconda riga dice a Git di ignorare tutti i file che finiscono con tilde (`~`), che è usata da alcuni editor di testo come Emacs per marcare i file temporanei. Puoi anche includere le directory `log`, `tmp` o `pid`, documenti generati automaticamente e così via. Definire un file `.gitignore` prima di iniziare generalmente è una buona idea, così eviti il rischio di committare accidentalmente dei file che non vuoi nel tuo repository Git. -Le regole per i pattern che puoi mettere nel file .gitignore sono le seguenti: +Queste sono le regole per i pattern che puoi usare in `.gitignore`: -* Linee vuote o linee che iniziano con # sono ignorate. -* I glob pattern standard (formati usati per indicare classi di caratteri nelle shell, ndt) funzionano. -* Puoi terminare i pattern con un diviso (`/`) per specificare una directory. -* Puoi negare un pattern aggiungendo all'inizio il punto di esclamazione (`!`). +* Le righe vuote o che inizino con `#` vengono ignorate. +* Gli standard `glob pattern` funzionano (http://it.wikipedia.org/wiki/Glob_pattern, ndt). +* Puoi terminare i pattern con uno slash (`/`) per indicare una directory. +* Puoi negare un pattern facendolo iniziare con un punto esclamativo (`!`). -I glob pattern sono come espressioni regolari semplificate usate dalla shell. Un asterisco (`*`) corrisponde a zero o più caratteri; `[abc]` corrispondente ad ogni carattere all'interno delle parentesi (in questo caso a, b, o c); il punto di domanda (`?`) corrispondente ad un singolo carattere; ed i caratteri all'interno delle parentesi quadre separati dal segno meno (`[0-9]`) corrispondono ad ogni carattere all'interno del range impostato (in questo caso da 0 a 9). +I `glob pattern` sono come espressioni regolari semplificate, usate dalla shell. L'asterisco (`*`) corrisponde a zero o più caratteri; `[abc]` corrisponde a ogni carattere all'interno delle parentesi (in questo caso `a`, `b`, o `c`); il punto interrogativo (`?`) corrisponden ad un carattere singolo; e i caratteri all'interno delle parentesi quadre separati dal segno meno (`[0-9]`) corrispondono ad ogni carattere all'interno dell'intervallo (in questo caso da 0 a 9). -Questo è un altro esempio di file .gitignore: +Questo è un altro esempio di file `.gitignore`: # un commento - questo è ignorato - # no file .a + # escludi i file .a *.a - # ma traccia lib.a, mentre vengono ignorati tutti i file .a come sopra + # ma traccia lib.a, sebbene su tu stia ignorando tutti i file `.a` !lib.a - # ignora solamente il file TODO in root, non del tipo subdir/TODO + # ignora solo il TODO nella root, e non subdir/TODO /TODO # ignora tutti i file nella directory build/ build/ @@ -183,28 +186,29 @@ Questo è un altro esempio di file .gitignore: # ignora tutti i file .txt nella directory doc/ doc/**/*.txt -Un pattern `**/` è disponibile in Git dalla version 1.8.2. +Il pattern `**/` è disponibile in Git dalla version 1.8.2. -### Visualizzare le Tue Modifiche Parcheggiate e Non ### +### Mostra le modifiche dentro e fuori lo `stage` ### -Se il comando `git status` è troppo vago per te — vorrai conoscere esattamente cosa hai modificato, non solamente i file che hai cambiato — puoi usare il comando `git diff`. Scopriremo in maggior dettaglio `git diff` più avanti; ma probabilmente lo userai più spesso per rispondere a queste due domande: Cosa hai modificato, ma non ancora parcheggiato? E cosa hai parcheggiato e che sta per mettere nel commit? Certamente, `git status` risponde a queste domande in generale, `git diff` ti mostra le linee esatte aggiunte e rimosse — la patch, per così dire. +Se `git status` è troppo vago per te - vuoi sapere cos'è stato effettivamente modificato e non solo quali file — puoi usare il comando `git diff`. Tratteremo più avanti `git diff` con maggior dettaglio, ma probabilmente lo userai molto spesso per rispondere a queste due domande: Cos'è che hai modificato ma non è ancora in `stage`? E cos'hai nello `stage` che non hai ancora committato? Sebbene `git status` risponda a queste domande in modo generico, `git diff` mostra le righe effettivamente aggiunte e rimosse — la patch così com'è. -Nuovamente ti chiedo di modificare e parcheggiare il file README e poi modificare il file benchmarks.rb senza parcheggiarlo. Se lanci il comando `status`, vedrai nuovamente questo: +Supponiamo che tu abbia modificato nuovamente `README` e `benchmarks.rb` ma messo nello `stage` solo il primo. Se esegui il comando `status`, vedrai qualcosa come questo: $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # new file: README - # - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # - # modified: benchmarks.rb - # - -Per vedere cosa hai modificato, ma non ancora parcheggiato, digita `git diff` senza altri argomenti: + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + new file: README + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + + +Per vedere cosa hai modificato, ma non ancora nello `stage`, digita `git diff` senza altri argomenti: $ git diff diff --git a/benchmarks.rb b/benchmarks.rb @@ -223,9 +227,9 @@ Per vedere cosa hai modificato, ma non ancora parcheggiato, digita `git diff` se log = git.commits('master', 15) log.size -Questo comando compara cosa c'è nella tua directory di lavoro con quello che è nella tua area di stage. Il risultato ti dice i cambiamenti che hai fatto che non sono ancora stati parcheggiati. +Questo comando confronta cosa c'è nella tua directory di lavoro con quello che c'è nella tua area di `stage`. Il risultato mostra le tue modifiche che ancora non hai messo nello `stage`. -Se vuoi vedere cosa hai parcheggiato e cosa sarà inviato con il tuo prossimo commit, puoi usare `git diff --cached`. (Nella versione 1.6.1 e successive di Git, puoi usare anche `git diff --staged`, che dovrebbe essere più facile da ricordare). Questo comando compara i tuoi cambiamenti nell'area di stage ed il tuo ultimo commit: +Se vuoi vedere cosa c'è nello `stage` e che farà parte della prossima commit, puoi usare `git diff --cached`. (Da Git 1.6.1 in poi, puoi usare anche `git diff --staged`, che dovrebbe essere più facile da ricordare). Questo comando confronta le modifiche che hai nell'area di `stage` e la tua ultima commit: $ git diff --cached diff --git a/README b/README @@ -240,25 +244,27 @@ Se vuoi vedere cosa hai parcheggiato e cosa sarà inviato con il tuo prossimo co + +Grit is a Ruby library for extracting information from a Git repository -É importante notare che `git diff` di per se non visualizza tutti i cambiamenti fatti dal tuo ultimo commit — solo i cambiamenti che ancora non sono parcheggiati. Questo può confondere, perché se hai messo in stage tutte le tue modifiche, `git diff` non darà nessun output. +È importante notare che `git diff` di per se non visualizza tutte le modifiche fatte dall'ultima commit, ma solo quelle che non sono ancora in `stage`. Questo può confondere, perché se hai messo in `stage` tutte le tue modifiche, `git diff` non mostrereà nulla. -Per un altro esempio, se parcheggi il file benchmarks.rb e lo modifichi, puoi usare `git diff` per vedere i cambiamenti nel file che sono in stage e i cambiamenti che non sono parcheggiati: +Ecco un altro esempio, se metti in `stage` il file `benchmarks.rb` e lo modifichi, puoi usare `git diff` per vedere quali modifiche al file sono in stage e i quali non ancora: $ git add benchmarks.rb $ echo '# test line' >> benchmarks.rb $ git status - # On branch master - # - # Changes to be committed: - # - # modified: benchmarks.rb - # - # Changes not staged for commit: - # - # modified: benchmarks.rb - # - -Ora puoi usare `git diff` per vedere cosa non è ancora parcheggiato + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: benchmarks.rb + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + + +Puoi quindi usare `git diff` per vedere cosa non è ancora in `stage` $ git diff diff --git a/benchmarks.rb b/benchmarks.rb @@ -271,7 +277,7 @@ Ora puoi usare `git diff` per vedere cosa non è ancora parcheggiato ##pp Grit::GitRuby.cache_client.stats +# test line -e `git diff --cached` per vedere cosa hai parcheggiato precedentemente: +e `git diff --cached` per vedere cos'è già in `stage`: $ git diff --cached diff --git a/benchmarks.rb b/benchmarks.rb @@ -290,143 +296,142 @@ e `git diff --cached` per vedere cosa hai parcheggiato precedentemente: log = git.commits('master', 15) log.size -### Eseguire il Commit delle Tue Modifiche ### +### Committa le tue modifiche ### -Ora la tua area di stage è impostata come volevi, puoi eseguire il commit delle tue modifiche. Ricorda che qualsiasi cosa che non è parcheggiata — qualsiasi file che hai creato o modificato e a cui non hai fatto `git add` — non andrà nel commit. Rimarranno come file modificati sul tuo disco. -In questo caso, l'ultima volta che hai lanciato `git status`, hai visto che tutto era parcheggiato, così sei pronto ad inviare le tue modifiche con un commit. Il modo più semplice per eseguire il commit è digitare `git commit`: +Ora che la tua area di stage è configurata come vuoi, puoi fare la commit delle tue modifiche. Ricorda che tutto ciò che non è in `stage` — qualsiasi file che hai creato o modificato per cui non hai fatto `git add` — non sarà nella commit. Rimarranno come file modificati sul tuo disco. +In questo caso, l'ultima volta che hai eseguito `git status`, hai visto che tutto era in `stage`, così sei pronto a committare le tue modifiche. Il modo più semplice per farlo è eseguire `git commit`: $ git commit -Facendo questo lanci l'editor che avevi scelto. (Questo è impostato nella tua shell dalla variabile di ambiente `$EDITOR` — generalmente vim o emacs, ovviamente puoi configurarlo con qualsiasi altro editor usando il comando `git config --global core.editor` come visto nel Capitolo 1). +Facendolo lanci il tuo editor predefinito. (Questo è impostato nella tua shell con la variabile di ambiente `$EDITOR` — generalmente vim o emacs, sebbene tu possa configurarlo con qualsiasi altro editor, usando il comando `git config --global core.editor` come hai visto nel *Capitolo 1*). -L'editor visualizzerà il seguente testo (questo è un esempio della schermata di Vim): +L'editor visualizzerà il testo (questo è un esempio della schermata di Vim): # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # On branch master # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # # new file: README # modified: benchmarks.rb + # ~ ~ ~ ".git/COMMIT_EDITMSG" 10L, 283C -Puoi vedere che il messaggio predefinito del commit contiene l'ultimo output del comando `git status`, commentato, e la prima riga in alto è vuota. Puoi rimuovere questi commenti ed inserire il tuo messaggio, o puoi lasciarli così per aiutarti a ricordare cosa hai inviato. (Per avere una nota di ricordo più esplicita puoi passare l'opzione `-v` a `git commit`. Così facendo inserirai i cambiamenti effettuati nell'editor in modo che tu possa vedere esattamente cosa hai fatto). Quando esci dall'editor, Git crea il tuo commit con un messaggio (con i commenti ed i cambiamenti eliminati). +Come vedi, il messaggio predefinito della commit contiene l'ultimo output del comando `git status`, commentato, e la prima riga in alto è vuota. Puoi rimuovere questi commenti e inserire il tuo messaggio di commit, o puoi lasciarli così per aiutarti a ricordare cosa stai committando. (Per una nota ancora più esplicita puoi usare l'opzione `-v` a `git commit`. Facendo saranno nel commento saranno inserite anche le modifiche stesse, così che tu possa vedere esattamente cosa hai fatto). Quando esci dall'editor, Git crea la tuo commit con un messaggio (rimuovendo commenti ed eventuali diff). -In alternativa, puoi inserire il messaggio del tuo commit in linea con il comando `commit` specificando dopo di esso l'opzione -m, come segue: +In alternativa, puoi inserire il messaggio per la tua commit alla riga di comando della `commit` specificando l'opzione -m, come segue: - $ git commit -m "Story 182: Fix benchmarks for speed" - [master]: created 463dc4f: "Fix benchmarks for speed" - 2 files changed, 3 insertions(+), 0 deletions(-) + $ git commit -m "Storia 182: Corretti benchmarks per la velocità" + [master 463dc4f] Storia 182: Corretti benchmarks per la velocità + 2 files changed, 3 insertions(+) create mode 100644 README -Ora hai creato il tuo primo commit! Puoi vedere che il commit ha riportato alcune informazioni sull'operazione: a quale ramo hai affidato il commit (`master`), quale checksum SHA-1 ha il commit (`463dc4f`), quanti file sono stati modificati e le statistiche sulle linee aggiunte e rimosse nel commit. +Hai creato la tua prima commit! Puoi vedere che la commit restituisce alcune informazioni su se stessa: su quale `branch` (ramo, ndt) hai fatto la commit (`master`), quale checksum SHA-1 ha la commit (`463dc4f`), quanti file sono stati modificati e le statistiche sulle righe aggiunte e rimosse con la commit. -Ricorda che il commit registra lo snapshot che hai impostato nella tua area di stage. Qualsiasi cosa che non hai parcheggiato rimarrà come modificata; puoi fare un altro commit per aggiungere questi alla storia del progetto. Ogni volta che fai un commit stai registrando una istantanea del tuo progetto, che puoi ripristinare o comparare successivamente. +Ricorda che la commit registra lo snapshot che hai salvato nella tua area di `stage`. Qualsiasi cosa che non è nello `stage` rimarrà lì come modificata; puoi fare un'altra commit per aggiungerli alla cronologia del progetto. Ogni volta che fai una commit, stai salvando un'istantanea (`snapshot`) del tuo progetto che puoi ripristinare o confrontare in seguito. -### Saltare l'Area di Stage ### +### Saltare l'area di stage ### -Anche se può essere estremamente utile per amministrare i commit esattamente come li vuoi, l'area di stage è molto più complessa di quanto tu possa averne bisogno nel lavoro normale. Se vuoi saltare l'area di parcheggio, Git fornisce una semplice scorciatoia. Passando l'opzione `-a` al comando `git commit` Git automaticamente parcheggia tutti i file che sono già stati tracciati facendo il commit, permettendoti di saltare la parte `git add`: +Sebbene sia estremamente utile per amministrare le commit come vuoi, l'area di stage è molto più complessa di quanto tu possa averne bisogno nel lavoro normale. Se vuoi saltare l'area di `stage`, Git fornisce una semplice accorciatoia. Con l'opzione `-a` al comando `git commit`, Git, committando, mette automaticamente nello `stage` tutti i file che erano già tracciati, permettendoti di saltare la parte `git add`: $ git status - # On branch master - # - # Changes not staged for commit: - # - # modified: benchmarks.rb - # + On branch master + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + + no changes added to commit (use "git add" and/or "git commit -a") $ git commit -a -m 'added new benchmarks' [master 83e38c7] added new benchmarks - 1 files changed, 5 insertions(+), 0 deletions(-) + 1 files changed, 5 insertions(+) -Nota come non hai bisogno, in questo caso, di lanciare `git add` sul file benchmarks.rb prima del commit. +Nota come in questo caso non hai bisogno di eseguire `git add` per benchmarks.rb prima della commit. -### Rimuovere File ### +### Rimuovere i file ### -Per rimuovere un file con Git, hai bisogno di rimuoverlo dai file tracciati (più precisamente, rimuoverlo dall'area di stage) e poi di fare il commit. Il comando `git rm` fa questo ed inoltre rimuove il file dalla tua directory di lavoro così non lo vedrai come un file non tracciato la prossima volta. +Per rimuovere un file da Git devi rimuoverlo dai file tracciati (più precisamente, rimuoverlo dall'area di `stage`) e quindi committare. Il comando `git rm` fa questo e lo rimuove dalla tua directory di lavoro, così che la prossima volta non lo vedrai come un file non tracciato. -Se semplicemente rimuovi il file dalla directory di lavoro, sarà visto sotto l'area "Changes not staged for commit" (cioè, _non parcheggiato_) dell'output `git status`: +Se rimuovi semplicemente il file dalla directory di lavoro, apparirà nella sezione "Changes not staged for commit" (cioè, _no in `stage`_) dell'output `git status`: $ rm grit.gemspec $ git status - # On branch master - # - # Changes not staged for commit: - # (use "git add/rm ..." to update what will be committed) - # - # deleted: grit.gemspec - # + On branch master + Changes not staged for commit: + (use "git add/rm ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + deleted: grit.gemspec + + no changes added to commit (use "git add" and/or "git commit -a") -Poi, se lanci `git rm`, parcheggia il file rimosso: +Se poi esegui `git rm`, la rimozione del file viene messa nello `stage`: $ git rm grit.gemspec rm 'grit.gemspec' $ git status - # On branch master - # - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # deleted: grit.gemspec - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + deleted: grit.gemspec + -La prossima volta che fai il commit, il file se ne andrà e non sarà più tracciato. Se modifichi il file e già aggiunto all'indice, devi forzarne la rimozione con l'opzione `-f`. Questa è una caratteristica di sicurezza per prevenire la rimozione accidentale dei dati che non sono ancora stati registrati in uno snapshot e che non possono essere recuperati da Git. +La prossima volta che committerai, il file sparirà e non sarà più tracciato. Se avevi già modificato il file e lo avevi aggiunto all'indice, devi forzarne la rimozione con l'opzione `-f`. Questa è una misura di sicurezza per prevenire la rimozione accidentale dei dati che non sono ancora stati salvati in uno `snapshot` e che non possono essere recuperati con Git. -Un'altra cosa utile che potresti voler fare è mantenere il file nel tuo albero di lavoro ma rimuoverlo dall'area di stage. In altre parole, vuoi mantenere il file sul tuo disco ma non vuoi che Git ne mantenga ancora traccia. Questo è particolarmente utile se ti dimentichi di aggiungere qualcosa al tuo file `.gitignore` ed accidentalmente lo aggiungi, come un lungo file di log od un gruppo di file `.a` compilati. Per fare questo, usa l'opzione `--cached`: +Un'altra cosa utile che potresti voler fare è mantenere il file nel tuo ambiente di di lavoro ma rimuoverlo dall'area di `stage`. In altre parole, vuoi mantenere il file sul tuo disco ma non vuoi che Git continui a tracciarlo. Questo è particolarmente utile se hai dimenticato di aggiungere qualcosa al tuo `.gitignore` e accidentalmente lo metti in `stage`, come un file di log molto grande o un gruppo di file compilati `.a`. Per farlo usa l'opzione `--cached`: $ git rm --cached readme.txt -Puoi passare file, directory o glob pattern di file al comando `git rm`. Questo significa che puoi fare cose come +Puoi passare file, directory o pattern glob di file al comando `git rm`. Questo significa che puoi fare $ git rm log/\*.log -Nota la barra inversa (`\`) di fronte a `*`. Questo è necessario perché Git ha una sua espansione dei nomi di file in aggiunta all'espansione dei filename della tua shell. Questo comando rimuove tutti i file che hanno l'estensione `.log` nella directory `log/`. O puoi fare qualcosa di simile a: +Nota la barra inversa (`\`) prima di `*`. Questo è necessario perché Git ha un'espansione propria dei nomi di file oltre a quella della tua shell. Questo comando rimuove tutti i file che hanno l'estensione `.log` nella directory `log/`. O puoi eseguire: $ git rm \*~ -Questo comando rimuove tutti i file che finiscono con `~`. +Per rimuovere tutti i file che finiscono con `~`. -### Muovere File ### +### Spostare i file ### -A differenza di altri sistemi VCS, Git non traccia esplicitamente i movimenti di file. Se rinomini un file in Git, nessun metadato è immagazzinato in Git che ti dirà che hai rinominato il file. Tuttavia, Git è abbastanza intelligente da capirlo dopo che è avvenuto — ci occuperemo di rilevare il movimento dei file più tardi. +A differenza di altri sistemi VCS, Git non traccia esplicitamente gli spostamenti dei file. Se rinomini un file in Git, nessun metadato viene salvato per dirgli che lo hai rinominato. Tuttavia, Git è abbastanza intelligente da capirlo dopo che l'hai fatto — più in la ci occuperemo di rilevare il movimento dei file. -Perciò crea un po' di confusione il fatto che Git abbia un comando `mv`. Se vuoi rinominare un file in Git, puoi lanciare qualcosa come +Può perciò creare un po' di confusione il fatto che Git abbia un comando `mv`. Se vuoi rinominare un file in Git puoi eseguire qualcosa come $ git mv file_from file_to -e questo funziona bene. Infatti, se lanci qualcosa come questo e guardi lo stato, vedrai che Git considera il file rinominato: +e funziona. Se, infatti, lanci un comando del genere e controlli lo stato, vedrai che Git considera il file rinominato: - $ git mv README.txt README + $ git mv README README.txt $ git status - # On branch master - # Your branch is ahead of 'origin/master' by 1 commit. - # - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # renamed: README.txt -> README - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + renamed: README -> README.txt + -Ovviamente, questo è equivalente a lanciare qualcosa come: +Ovviamente, questo è equivalente a eseguire: - $ mv README.txt README - $ git rm README.txt - $ git add README + $ mv README README.txt + $ git rm README + $ git add README.txt -Git capisce implicitamente che è stato rinominato, così non è un problema rinominare un file in questo modo o con il comando `mv`. L'unica reale differenza è che `mv` è un solo comando invece di tre — è un comando di convenienza. Più importante è che tu puoi usare qualsiasi strumento per rinominare un file, ed aggiungere/togliere più tardi, prima di un commit. +Git capisce che, implicitamente stai rinominando il file, così che non c'è differenza se rinominare un file in questo modo o con il comando `mv`. L'unica differenza reale è che `mv` è un solo comando invece di tre: è un questione di convenienza. La cosa più importante è che puoi usare qualsiasi strumento per rinominare un file, e gestire l'aggiunta/rimozione più tardi, prima della commit. -## Vedere la Storia dei Commit ## +## Vedere la cronologia delle commit ## -Dopo che hai creato un po' di commit, o se hai clonato un repository che contiene una storia di commit, probabilmente vuoi guardare indietro per vedere cosa è successo. Lo strumento base e più potente per farlo è il comando `git log`. +Dopo che avrai creato un po' di commit, o se hai clonato un repository che già ha la sua cronologia di commit, vorrai probabilmente guardare cos'è successo nel passato. Lo strumento essenziale e quello più potente per farlo è il comando `git log`. -Questi esempi usano un progetto veramente semplice chiamato simplegit che è spesso usato per le dimostrazioni. Per ottenere il progetto, lancia: +Questi esempi usano un progetto veramente semplice chiamato `simplegit` che uso spesso per gli esempi. Per ottenere il progetto, esegui git clone git://github.com/schacon/simplegit-progit.git -Quando lanci `git log` in questo progetto, dovresti avere un output che assomiglia a questo: +Quando esegui `git log` in questo progetto, dovresti avere un output che assomiglia a questo: $ git log commit ca82a6dff817ec66f44342007202690a93763949 @@ -447,11 +452,11 @@ Quando lanci `git log` in questo progetto, dovresti avere un output che assomigl first commit -In modo predefinito, senza argomenti, `git log` mostra i commit fatti nel repository in ordine cronologico inverso. Così, il commit più recente è mostrato all'inizio. Come puoi vedere, questo comando elenca ogni commit con il suo codice SHA-1, il nome dell'autore e la sua e-mail, la data di scrittura ed il messaggio di invio. +In modo predefinito, senza argomenti, `git log` mostra le commit fatte nel repository in ordine cronologico inverso. In questo modo la commit più recente è la prima ad apparire. Come vedi, questo comando elenca ogni commit con il suo codice SHA-1, il nome e l'email dell'autore, la data di salvataggio e il messaggio della commit. -Un enorme numero e varietà di opzioni da passare al comando `git log` sono disponibili per vedere esattamente cosa si sta cercando. Qui, vedremo alcune opzioni più usate. +Sono disponibili moltissime opzioni da passare al comando `git log` per vedere esattamente quello che stai cercando. Qui ne vedremo alcune tra quelle più usate. -Una delle opzioni più utili è `-p`, che mostra l'introduzione del diff di ogni commit. Puoi anche usare `-2`, che limita l'output solamente agli ultimi due ingressi: +Una delle opzioni più utili è `-p`, che mostra le differenze introdotte da ciascuna commit. Puoi usare anche `-2`, che limita l'output agli ultimi due elementi: $ git log -p -2 commit ca82a6dff817ec66f44342007202690a93763949 @@ -464,11 +469,13 @@ Una delle opzioni più utili è `-p`, che mostra l'introduzione del diff di ogni index a874b73..8f94139 100644 --- a/Rakefile +++ b/Rakefile - @@ -5,7 +5,7 @@ require 'rake/gempackagetask' + @@ -5,5 +5,5 @@ require 'rake/gempackagetask' spec = Gem::Specification.new do |s| + s.name = "simplegit" - s.version = "0.1.0" + s.version = "0.1.1" s.author = "Scott Chacon" + s.email = "schacon@gee-mail.com commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 Author: Scott Chacon @@ -491,28 +498,29 @@ Una delle opzioni più utili è `-p`, che mostra l'introduzione del diff di ogni -end \ No newline at end of file -Questa opzione visualizza le stessi informazioni ma direttamente seguita dal diff di ogni voce. Questo è veramente utile per la revisione del codice o per sfogliare velocemente cosa è successo in una serie di commit che un collaboratore ha aggiunto. +Quest'opzione mostra le stessi informazioni ma ciascun elemento è seguito dalle differenze. Questo è molto utile per revisionare il codice o per dare un'occhiata veloce a cosa è successo in una serie di commit che un collaboratore ha aggiunto. -Qualche volta è più semplice controllare i cambiamenti per parole piuttosto che per linee. Esiste un'opzione `--word-diff` disponibile in Git, che puoi aggiungere al comando `git log -p` per ottenere un word diff (differenza per parole, ndt) invece del normale diff linea per linea. Il formato Word diff è piuttosto inutile quando applicato al codice sorgente, ma diviene utile quando applicato a grandi file di testo, come libri o la tua dissertazione. Ecco un esempio: +Qualche volta è più semplice verificare le singole modifiche piuttosto che intere righe. Per questo in Git è disponibile l'opzione `--word-diff`, che puoi aggiungere al comando `git log -p` per vedere le differenze tra le parole invece di quella normale, linea per linea. Il formato `word diff` è piuttosto inutile quando applicato al codice sorgente, ma diventa utile quando applicato a grandi file di testo, come i libri o la tua tesi. Ecco un esempio: $ git log -U1 --word-diff - commit da734f4151c0bf92798edd67fb571f86ab4179e6 - Author: Jed Hartman - Date: Tue Mar 19 18:00:35 2013 -0700 - - Added a missing "in" to a sentence. + commit ca82a6dff817ec66f44342007202690a93763949 + Author: Scott Chacon + Date: Mon Mar 17 21:52:11 2008 -0700 - diff --git a/en/01-chapter2.markdown b/en/01-chapter2.markdown - index 879e48c..a992ff3 100644 - --- a/en/01-chapter2.markdown - +++ b/en/01-chapter2.markdown - @@ -553,3 +553,3 @@ You may be wondering what the difference is + changed the version number - This option adds a nice little ASCII graph showing your branch and merge history, which we can see {+in+} our copy of the Grit project repository: + diff --git a/Rakefile b/Rakefile + index a874b73..8f94139 100644 + --- a/Rakefile + +++ b/Rakefile + @@ -7,3 +7,3 @@ spec = Gem::Specification.new do |s| + s.name = "simplegit" + s.version = [-"0.1.0"-]{+"0.1.1"+} + s.author = "Scott Chacon" -Come puoi vedere, non ci sono linee aggiunte o rimosse in questo output come in un normale diff. Invece i cambiamenti sono mostrati sulla linea. Puoi vedere la parola racchiusa in `{+ +}` (parole rimosse sarebbe state mostrate come `[-removed-]`). Potresti anche volere ridurre le solite tre linee di contesto nell'output di diff a solo una linea, dato che il contesto è ora costituito da parole, non linee. Puoi farlo con `-U1` come abbiamo fatto nell'esempio qui sopra. +Come puoi vedere, non ci sono righe aggiunte o rimosse in questo output, come in una normale differenza. I cambiamente sono invece mostrati sulla stessa riga. Puoi vedere la parola aggiunta racchiusa tra `{+ +}` e quella rimossa tra `[- -]`. Potresti anche volere ridurre le solite tre righe di contesto dall'output delle differenze a una sola, poiché ora il contesto è costituito da parole e non righe. Puoi farlo con `-U1`, come abbiamo fatto nell'esempio qui sopra. -Puoi anche usare una serie di opzioni di riassunto con `git log`. Per esempio, se vuoi vedere alcune statistiche brevi per ogni commit, puoi usare l'opzione `--stat`: +Puoi usare anche una serie di opzioni di riassunto con `git log`. Per esempio, se vuoi vedere alcune statistiche brevi per ciascuna commit, puoi usare l'opzione `--stat`: $ git log --stat commit ca82a6dff817ec66f44342007202690a93763949 @@ -522,7 +530,7 @@ Puoi anche usare una serie di opzioni di riassunto con `git log`. Per esempio, s changed the version number Rakefile | 2 +- - 1 files changed, 1 insertions(+), 1 deletions(-) + 1 file changed, 1 insertion(+), 1 deletion(-) commit 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 Author: Scott Chacon @@ -531,7 +539,7 @@ Puoi anche usare una serie di opzioni di riassunto con `git log`. Per esempio, s removed unnecessary test code lib/simplegit.rb | 5 ----- - 1 files changed, 0 insertions(+), 5 deletions(-) + 1 file changed, 5 deletions(-) commit a11bef06a3f659402fe7563abf99ad00de2209e6 Author: Scott Chacon @@ -542,45 +550,50 @@ Puoi anche usare una serie di opzioni di riassunto con `git log`. Per esempio, s README | 6 ++++++ Rakefile | 23 +++++++++++++++++++++++ lib/simplegit.rb | 25 +++++++++++++++++++++++++ - 3 files changed, 54 insertions(+), 0 deletions(-) + 3 files changed, 54 insertions(+) -Come puoi vedere, l'opzione `--stat` stampa sotto ogni voce di commit una lista dei file modificati, quanti file sono stati modificati, e quante linee in questi file sono state aggiunte o rimosse. Inoltre aggiunge un resoconto delle informazioni alla fine. -Un'altra opzione veramente utile è `--pretty`. Questa opzione modifica gli output di log per la formattazione rispetto a quella predefinita. Alcune opzioni pre-costruite sono pronte all'uso. L'opzione `oneline` stampa ogni commit in una singola linea, che è utile se stai guardando una lunga serie di commit. In aggiunta le opzioni `sort`, `full` e `fuller` mostrano l'output pressapoco nello stesso modo ma con più o meno informazioni, rispettivamente: +Come puoi vedere, l'opzione `--stat` visualizza sotto ogni commit la lista dei file modificati, quanti file sono stati modificati, e quante righe in questi file sono state aggiunte e rimosse. Alla fine aggiunge anche un resoconto delle informazioni. +Un'altra opzione veramente utile è `--pretty`. Questa opzione modifica gli output di log rispetto a quella predefinita. Alcune opzioni predefinite sono pronte per l'uso. L'opzione `oneline` visualizza ogni commit su una singola linea, che è utile se stai controllando una lunga serie di commit. In aggiunta le opzioni `short`, `full` e `fuller` mostrano più o meno lo stesso output ma con più o meno informazioni, rispettivamente: $ git log --pretty=oneline ca82a6dff817ec66f44342007202690a93763949 changed the version number 085bb3bcb608e1e8451d4b2432f8ecbe6306e7e7 removed unnecessary test code a11bef06a3f659402fe7563abf99ad00de2209e6 first commit -L'opzione più interessante è `format`, che ti permette di specificare la tua formattazione dell'output di log. Questa è specialmente utile quando stai generando un output da analizzare su una macchina — perché specifichi in modo preciso il formato, sai che non cambierà con gli aggiornamenti di Git: +L'opzione più interessante è `format`, che ti permette di specificare la formattazione dell'output di log. Questa è specialmente utile quando stai generando un output che sarà analizzo da una macchina, perché specificando esplicitamente il formato, sai che non cambierà con gli aggiornamenti di Git: $ git log --pretty=format:"%h - %an, %ar : %s" ca82a6d - Scott Chacon, 11 months ago : changed the version number 085bb3b - Scott Chacon, 11 months ago : removed unnecessary test code a11bef0 - Scott Chacon, 11 months ago : first commit -La Tabella 2-1 elenca alcune delle opzioni più utili da usare. +Table 2-1 lists some of the more useful options that format takes. + + Opzione Descrizione dell'output - %H Hash commit - %h Hash commit abbreviato - %T Hash tree - %t Hash tree abbreviato - %P Hash genitore - %p Hash genitore abbreviati - %an Nome autore - %ae E-mail autore - %ad Data autore (rispetta il formato dell'opzione –date= ) - %ar Data autore, relativa - %cn Nome di chi ha fatto il commit - %ce E-mail di chi ha fatto il commit - %cd Data di chi ha fatto il commit - %cr Data di chi ha fatto il commit, relativa + %H Hash della commit + %h Hash della commit abbreviato + %T Hash dell'albero + %t Hash dell'albero abbreviato + %P Hash del genitore + %p Hash del genitore abbreviato + %an Nome dell'autore + %ae e-mail dell'autore + %ad Data di commit dell'autore (il formato rispetta l'opzione --date=) + %ar Data relativa di commit dell'autore + %cn Nome di chi ha fatto la commit (`committer`, in inglese) + %ce e-mail di chi ha fatto la commit + %cd Data della commit + %cr Data relativa della commit %s Oggetto -Sarai sorpreso dalla differenza tra _author_ (l'autore) e _committer_ (chi ha eseguito il commit). L'autore è la persona che ha scritto originariamente il lavoro, mentre chi ha eseguito il commit è la persona che per ultima ha applicato il lavoro. Così, se invii una patch ad un progetto ed uno dei membri del progetto applica la patch, entrambi sarete riconosciuti — tu come l'autore ed il membro del progetto come colui il quale ha eseguito il commit. Scopriremo meglio questa distinzione nel Capitolo 5. +Potresti essere sorpreso dalla differenza tra autore e _committer_ (chi ha eseguito la commit). L'autore è la persona che ha scritto la modifica, mentre il _committer_ è l'ultima persona che ha applicato la modifica. Così, se invii una modifica a un progetto ed uno dei membri principali del progetto la applica, ne avranno entrambi il riconoscimento — tu come l'autore ed il membro del progetto come chi l'ha committata. Vedremo meglio questa distinzione nel *Capitolo 5*. -Le opzioni oneline e format sono particolarmente utili con un'altra opzione `log` chiamata `--graph`. Questa opzione aggiunge un grafico ASCII carino che mostra le diramazioni e le unioni della storia, che possiamo vedere nella copia del repository del progetto Grit: +Le opzioni `oneline` e `format` sono particolarmente utili con un'altra opzione di `log` chiamata `--graph`. Questa aggiunge un piccolo grafico ASCII carino che mostra le diramazioni e le unioni della cronologia, che possiamo vedere nella copia del repository del progetto Grit: $ git log --pretty=format:"%h %s" --graph * 2d3acf9 ignore errors from SIGCHLD on trap @@ -596,46 +609,103 @@ Le opzioni oneline e format sono particolarmente utili con un'altra opzione `log Queste sono solo alcune opzioni semplici per la formattazione dell'output di `git log` — ce ne sono altre. La tabella 2-2 elenca le opzioni che abbiamo visto prima e altre opzioni comunemente usate che possono essere utili per cambiare l'output del comando log. + + Opzione Descrizione - -p Mostra la patch introdotta per ogni commit. - --word-diff Mostra la patch nel formato word diff. + -p Mostra la modifica introdotta con ogni commit. + --word-diff Mostra la modifica nel formato `word diff`. --stat Mostra le statistiche per i file modificati in ogni commit. - --shortstat Mostra solo le linee cambiate/inserite/cancellate dal comando --stat. - --name-only Mostra la lista dei file modificati dopo le informazione del commit. - --name-status Mostra la lista dei file con le informazioni di aggiunte/modifiche/rimozioni. - --abbrev-commit Mostra solo i primi caratteri del codice checksum SHA-1 invece di tutti e 40. - --relative-date Mostra la data in un formato relativo (per esempio, "2 week ago", "2 settimane fa") invece di usare l'intero formato della data. - --graph Mostra un grafico ASCII dei rami e delle unioni della storia accando all'output di log. - --pretty Mostra i commit in un formato alternativo. L'opzione include oneline, short, full, fuller, e format (dove hai specificato la tua formattazione). + --shortstat Mostra solo le righe cambiate/aggiunte/rimosse del comando --stat. + --name-only Mostra l'elenco dei file modificati dopo le informazione della commit. + --name-status Mostra l'elenco dei file con le informazioni aggiunte/modifiche/eliminate. + --abbrev-commit Mostra solo i primi caratteri del codice SHA-1 invece di tutti i 40. + --relative-date Mostra la data in un formato relativo (per esempio, "2 week ago", "2 settimane fa") invece di usare il formato completo della data. + --graph Mostra un grafico ASCII delle diramazioni e delle unioni della cronologia insieme all'output del log. + --pretty Mostra le commit in un formato alternativo. L'opzione include oneline, short, full, fuller, e format (quando specifichi un tuo formato). --oneline Un'opzione di convenienza abbreviazione per `--pretty=oneline --abbrev-commit`. -### Limitare l'Output di Log ### +### Limita l'output del log ### -Oltre alle opzioni per la formattazione dell'output, git log accetta un numero di opzioni di limitazione — cioè, opzioni che ti permettono di vedere solo alcuni commit. Hai già visto una opzione del genere — l'opzione `-2`, che mostra solamente gli ultimi due commit. Infatti, puoi fare `-`, dove `n` è un intero per vedere gli ultimi `n` commit. In realtà, non userai spesso questa possibilità, perché Git di base veicola tutti gli output attraverso un impaginatore così vedrai solamente una pagina di log alla volta. +Oltre alle opzioni per la formattazione dell'output, `git log` accetta una serie di utili opzioni restrittive, ovvero opzioni che ti permettono di vedere solo alcune commit. Abbiamo già visto una opzione del genere, l'opzione `-2`, che mostra solamente le ultime due commit. Infatti, puoi usare `-`, dove `n` è un intero, per vedere le ultime `n` commit. In realtà non la userai spesso, perché Git accoda tutti gli output paginandoli, così vedrai solamente una pagina alla volta. -Ovviamente, le opzioni di limitazione temporali come `--since` e `--until` sono molto utili. Per esempio, questo comando prende la lista dei commit fatti nelle ultime due settimane: +Le opzioni temporali come `--since` e `--until` sono invece molto utili. Questo comando, per esempio, prende la lista dei commit fatti nelle ultime due settimane: $ git log --since=2.weeks Questo comando funziona con molti formati — puoi specificare una data (“2008-01-15”) o una data relativa come “2 years 1 day 3 minutes ago”. -Puoi inoltre filtrare l'elenco dei commit che corrispondono a dei criteri di ricerca. L'opzione `--author` ti permette di filtrare uno specifico autore e l'opzione `--grep` permette di cercare delle parole chiave nei messaggi dei commit. (Nota che se vuoi specificare sia le opzioni author e grep, devi aggiungere `--all-match` o il comando ricercherà i commit sia di uno sia di quell'altro.) +Puoi inoltre filtrare l'elenco delle commit che corrispondono a dei criteri di ricerca. L'opzione `--author` ti permette di filtrare per uno specifico autore e l'opzione `--grep` ti permette di cercare delle parole chiave nei messaggi delle commit. (Nota che specifichi entrambe le opzioni il comando cercherà le commit che corrispondano a tutte le opzioni specificate.) -L'ultima opzione di filtro veramente utile da passare a `git log` è un percorso. Se specifichi una directory o un nome di file, puoi limitare l'output del log ai commit che introducono modifiche a questi file. E' sempre l'ultima opzione fornita ed è generalmente preceduta dal doppio meno (`--`) per separare i path dalle opzioni. +Se vuoi specificare più opzioni `--grep` alternative devi usare `--all-match`. -Nella tabella 2-3 vediamo una lista di riferimento di queste e di altre opzioni comuni. +L'ultima opzione di `git log` per il filtraggio è il percorso. Se specifichi il nome di una directory o di un file, puoi limitare l'output del log alle sole commit che introducono modifiche a quei file. Questa è sempre l'ultima opzione specificata e generalmente è preceduta dal doppio meno (`--`) per separare i percorsi dalle opzioni. - Opzioni Descrizione - -(n) Vedi solo gli ultimi n commit - --since, --after Limita ai commit fatti prima o dopo una data specificata. - --until, --before Limita ai commit fatti prima o fino ad una specifica data. - --author Visualizza solo i commit in cui l'autore corrisponde alla stringa specificata. - --committer Visualizza solo i commit dove chi ha eseguito il commit corrisponde alla stringa specificata. +Nella tabella 2-3 vediamo una lista di riferimento di queste e di altre opzioni comuni. -Per esempio, se vuoi vedere quali commit modificano i file nella storia del codice sorgente di Git dove Junio Hamano ha eseguito i commit e non sono stati unificati nel mese di Ottobre del 2008, puoi lanciare qualcosa di simile a: + - $ git log --pretty="%h - %s" --author=gitster --since="2008-10-01" \ - --before="2008-11-01" --no-merges -- t/ + Opzioni Descrizione + -(n) Vedi solo le ultime n commit + --since, --after Mostra solo le commit fatte dalla data specificata. + --until, --before Mostra solo le commit fatte entro la data specificata. + --author Mostra solo le commit dell'autore specificato. + --committer Mostra solo le commit del committer specificato. + + +### Filtrare i risultati in base a data e ora ### + + Per sapere cosa è stato committato nel repository di Git (git://git.kernel.org/pub/scm/git/git.git) il 29/04/2014 (usando come riferimento il fuso orario impostato sul tuo computer) + + $ git log --after="2014-04-29 00:00:00" --before="2014-04-29 23:59:59" \ + --pretty=fuller + + Il risultato che si ottiene eseguendo questo comando cambia in base al fuso orario dove viene eseguito. È quindi consigliato usare un orario assoluto quando si usano le opzioni `--after` e `--before`, come per esempio l'ISO 8601 (che include anche informazioni sul furo orario), così da ottenere gli stessi risultati indipendentemente dal fuso orario. + +Per ottenere le commit eseguite in un determinato istante (per esempio il 29 Aprile 2013 alle 17:07:22 CET), possiamo eseguire: + + $ git log --after="2013-04-29T17:07:22+0200" \ + --before="2013-04-29T17:07:22+0200" --pretty=fuller + + commit de7c201a10857e5d424dbd8db880a6f24ba250f9 + Author: Ramkumar Ramachandra + AuthorDate: Mon Apr 29 18:19:37 2013 +0530 + Commit: Junio C Hamano + CommitDate: Mon Apr 29 08:07:22 2013 -0700 + + git-completion.bash: lexical sorting for diff.statGraphWidth + + df44483a (diff --stat: add config option to limit graph width, + 2012-03-01) added the option diff.startGraphWidth to the list of + configuration variables in git-completion.bash, but failed to notice + that the list is sorted alphabetically. Move it to its rightful place + in the list. + + Signed-off-by: Ramkumar Ramachandra + Signed-off-by: Junio C Hamano + +Data e ora di `AuthorDate` e `CommitDate` hanno un formato standard (`--date=default`) che mostra le informazioni sul fuso orario, rispettivamente, dell'autore e di chi ha eseguito la commit. + +Altri formati utili sono `--date=iso` (ISO 8601), `--date=rfc` (RFC 2822), `--date=raw` (i secondi passati dall'1/1/1970 UTC) `--date=local` (l'orario del tuo attuale fuso) e `--date=relative` (per esempio: "2 ore fa"). + +Usando `git log` senza specificare un orario equivale a specificare l'orario attuale del tuo computer (mantenendo la differenza con l'UTC). + +Per esempio, eseguendo `git log` alle 09:00 su un computer che sia 3 ore avanti rispetto all'UTC, rende equivalenti questi comandi: + + $ git log --after=2008-06-01 --before=2008-07-01 + $ git log --after="2008-06-01T09:00:00+0300" \ + --before="2008-07-01T09:00:00+0300" + +Per fare un ultimo esempio, se vuoi vedere quale commit di Junio Hamano dell'ottobre del 2008 (relative al fuso di New York) che modificano i file di test nella cronologia dei sorgenti di Git che non sono ancora state unite con merge, puoi eseguire questo: + + $ git log --pretty="%h - %s" --author=gitster \ + --after="2008-10-01T00:00:00-0400" \ + --before="2008-10-31T23:59:59-0400" --no-merges -- t/ 5610e3b - Fix testcase failure when extended attribute acd3b9e - Enhance hold_lock_file_for_{update,append}() f563754 - demonstrate breakage of detached checkout wi @@ -643,126 +713,127 @@ Per esempio, se vuoi vedere quali commit modificano i file nella storia del codi 51a94af - Fix "checkout --track -b newbranch" on detac b0ad11e - pull: allow "git pull origin $something:$cur -Ci sono circa 20,000 commit nella storia del codice sorgente di git, questo comando mostra 6 righe corrispondenti ai termini di ricerca. +Ci sono circa 20,000 commit nella cronologia dei sorgenti di git, questo comando mostra 6 righe che corrispondono ai termini della ricerca. -### Usare una GUI per Visualizzare la Storia ### +### Usare una GUI per visualizzare la cronologia ### -Se vuoi usare uno strumento più grafico per visualizzare la storia dei tuoi commit, puoi vedere un programma in Tck/Tk chiamato gitk che è distribuito con Git. Gitk è fondamentalmente uno strumento visuale come `git log`, e accetta circa tutte le opzioni di filtro che `git log` ha. Se digiti gitk dalla riga di comando del tuo progetto, dovresti vedere qualcosa di simile alla Figura 2-2. +Se vuoi usare uno strumento più grafico per visualizzare la cronologia delle tue commit, puoi provare un programma in Tck/Tk chiamato `gitk` che viene distribuito con Git. Gitk è fondamentalmente uno strumento grafico come `git log`, e accetta quasi tutte le opzioni di filtro supportate da `git log`. Se digiti `gitk` dalla riga di comando nel tuo progetto, dovresti vedere qualcosa di simile alla Figura 2-2. Insert 18333fig0202.png -Figura 2-2. Il visualizzatore della storia gitk. +Figura 2-2. Il grafico della cronologia con gitk. -Puoi vedere la storia dei commit nella metà alta della finestra con un grafico genealogico. La finestra di diff nella metà inferiore mostra i cambiamenti introdotti ad ogni commit che selezioni. +Puoi vedere la cronologia delle commit, nella metà superiore, della finestra come un albero genealogico carino. La finestra delle differenza, nella metà inferiore, mostra le modifiche introdotte con ciascuna commit che selezioni. -## Annullare le Cose ## +## Annullare qualcosa ## -Ad ogni stadio potresti voler annullare qualcosa. Qui, vedremo alcuni strumenti fondamentali per annullare i cambiamenti che hai fatto. Attenzione, perché non sempre puoi invertire alcuni annullamenti. Questa è una delle aree in Git dove puoi perdere qualche lavoro se sbagli. +In qualsiasi momento puoi voler annullare qualcosa. Rivedremo alcuni strumenti basilari per annullare le modifiche fatte. Attenzione però, perché non sempre puoi ripristinare ciò che annulli. Questa è una delle aree di Git dove puoi perdere del lavoro svolto se commetti un errore. -### Modificare il Tuo Ultimo Commit ### +### Modifica la tua ultima commit ### -Uno degli annullamenti comuni avviene quando invii troppo presto un commit e magari dimentichi di aggiungere alcuni file, o sbagli il messaggio di commit. Se vuoi provare nuovamente questo commit, puoi lanciare commit con l'opzione `--amend`: +Uno degli annullamenti più comuni si verifica quando committi qualcosa troppo presto e magari dimentichi di aggiungere qualche file, o sbagli qualcosa nel messaggio di commit. Se vuoi modificare questa commit puoi eseguire il comando commit con l'opzione `--amend`: $ git commit --amend -Questo comando prende la tua area di stage e la usa per il commit. Se non hai fatto cambiamenti dal tuo ultimo commit (per esempio, lanci questo comando subito dopo il tuo commit precedente), allora il tuo snapshot sarà esattamente uguale e potrai cambiare il tuo messaggio di commit. +Questo comando usa la tua area di `stage` per la commit. Se non hai fatto modifiche dalla tua ultima commit (per esempio, esegui questo comando subito dopo la tua commit precedente), allora il tuo snapshot sarà identico e potrai cambiare il tuo messaggio di commit. -L'editor per il messaggio del commit apparirà, ma già contiene il messaggio del commit precedente. Puoi modificare il messaggio come sempre, ma sovrascriverà il commit precedente. +Verrà lanciata la stessa applicazione per scrivere il messaggio della commit, ma conterrà già il messaggio della commit precedente. Puoi modificare il messaggio normalmente, ma questo sovrascriverà la commit precedente. -Come esempio, se fai il commit e poi realizzi di aver dimenticato un cambiamento nella tua area di stage di un file e vuoi aggiungerlo a questo commit, puoi farlo così: +Per esempio, se fai una commit e realizzi di non aver messo nello `stage` le modifiche a un file e vuoi aggiungerlo a questa commit, puoi fare così: $ git commit -m 'initial commit' $ git add forgotten_file $ git commit --amend -Tutti e tre i comandi finisco in un singolo commit — il secondo commit riscrive il risultato del primo. +Dopo questi tre comandi ti ritroverai con una sola commit: la seconda sovrascrive la prima. -### Disimpegnare un File Staged ### +### Rimuovere un file dall'area di `stage` ### -Le prossime due sezioni mostrano come gestire le modifiche della tua area di stage e della directory di lavoro. La parte divertente è che il comando che usi per determinare lo stato di queste due aree ricorda come annullare i cambiamenti fatti. Per esempio, supponiamo che hai modificato due file e vuoi inviarli come modifiche separate, ma accidentalmente digiti `git add *` e li parcheggi entrambi. Come puoi disimpegnare uno dei due? Il comando `git status` ti ricorda: +Le prossime due sezioni mostrano come gestire le modifiche della tua area di stage e della directory di lavoro. La parte divertente è che il comando che usi per determinare lo stato di queste due aree ti ricorda come annullare le modifiche alle stesse. Per esempio, supponiamo che hai modificato due file e vuoi committarli come modifiche separate, ma accidentalmente digiti `git add *` e li metti entrambi in `stage`. Come puoi rimuoverne uno? Il comando `git status` ti ricorda: $ git add . $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # modified: README.txt - # modified: benchmarks.rb - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: README.txt + modified: benchmarks.rb + -Ora il testo sotto “Changes to be committed”, dice di usare `git reset HEAD ...` per annullare. Così, usa questo avviso per disimpegnare il file benchmarks.rb dal parcheggio: +Il testo sotto “Changes to be committed” ti dice di usare `git reset HEAD ...` per rimuovere dallo `stage`. Usa quindi questo consiglio per rimuoever `benchmarks.rb`: $ git reset HEAD benchmarks.rb - benchmarks.rb: locally modified + Unstaged changes after reset: + M benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # modified: README.txt - # - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # (use "git checkout -- ..." to discard changes in working directory) - # - # modified: benchmarks.rb - # - -Il comando è un po' strano, ma funziona. Il file benchmarks.rb è modificato ma non parcheggiato. - -### Annullare le Modifiche di un File Modificato ### - -Come fare se hai realizzato che non vuoi più tenere le modifiche che hai fatto al file `benchmarks.rb`? Come puoi annullarle facilmente — ritornare a come era al tuo ultimo commit (o alla clonazione iniziale, o come lo avevi nella tua directory di lavoro)? Fortunatamente, `git status` ci dice come farlo. Nell'ultimo output di esempio, l'area di unstage (file non parcheggiati) assomiglia a: - - # Changes not staged for commit: - # (use "git add ..." to update what will be committed) - # (use "git checkout -- ..." to discard changes in working directory) - # - # modified: benchmarks.rb - # - -Ci dice abbastanza esplicitamente come annullare le modifiche fatte (al limite, le nuove versioni di Git, 1.6.1 e successive, lo fanno — se hai una versione più vecchia è raccomandato aggiornarla per avere queste funzioni utili). Vediamo cosa ci dice: + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: README.txt + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + + +Il comando è un po' strano, ma funziona. Il file `benchmarks.rb` ora è modificato ma non più nello `stage`. + +### Annullare le modifiche a un file ### + +Come fare se ti rendi conto che non vuoi più mantenere le modifiche di `benchmarks.rb`? Come puoi annullarle facilmente — ritornare a come era prima dell'ultima commit (o al clone iniziale, o comunque lo avevi nella tua directory di lavoro)? Fortunatamente `git status` ti dice come farlo. Nell'ultimo output di esempio, l'area dei file modificati appare così: + + Changes not staged for commit: + (use "git add ..." to update what will be committed) + (use "git checkout -- ..." to discard changes in working directory) + + modified: benchmarks.rb + + +Ti dice abbastanza chiaramente come annullare le tue modifiche (almeno le nuove versioni di Git, dalla 1.6.1 in poi, lo fanno: se hai una versione più vecchia ti raccomandiamo di aggiornarla per avere alcune di queste funzioni utili e carine). Vediamo cosa dice: $ git checkout -- benchmarks.rb $ git status - # On branch master - # Changes to be committed: - # (use "git reset HEAD ..." to unstage) - # - # modified: README.txt - # + On branch master + Changes to be committed: + (use "git reset HEAD ..." to unstage) + + modified: README.txt + -Puoi vedere come le modifiche sono state annullate. Dovresti inoltre realizzare che è un comando pericoloso: ogni cambiamento fatto al file è sparito — semplicemente hai copiato un altro file su di esso. Non usare mai questo comando a meno che non sai assolutamente che non vuoi il file. Se hai bisogno solamente di toglierlo di torno, vedremo ripostigli e ramificazioni nei capitoli successivi ; queste sono generalmente le vie migliori da seguire. +Puoi vedere come le modifiche siano state annullate. Dovresti capire quanto questo sia un comando pericoloso: tutte le modifiche fatte al file sono sparite: lo hai praticamente sovrascritto con un altro file. Non usare mai questo comando a meno che non sia assolutamente certo di non volere il file. Se hai solo bisogno di toglierlo di torno, vedremo i `ripostigli` (*stash*) e le diramazioni (*branch*) nei prossimi capitoli, che generalmente sono le strade migliori da seguire. -Ricorda, qualsiasi cosa che è stata affidata a Git può quasi sempre essere recuperata. Tutti i commit che erano su rami che sono stati cancellati o sovrascritti tramite un commit `--amend` possono essere recuperati (vedi il *Capitolo 9* per il recupero dei dati). Tuttavia, qualsiasi cosa che perdi e che non è stata affidata a Git probabilmente non sarà mai più visto. +Ricorda: qualsiasi cosa che sia stata committata in Git può quasi sempre essere recuperata. Tutte le commit che erano sulle diramazioni che sono state cancellate o sovrascritte con una commit `--amend` possono essere recuperate (vedi il *Capitolo 9* per il recupero dei dati). Ma qualsiasi cosa che perdi che non sia stata mai committata non la vedrai mai più. -## Lavorare con Sorgenti Remote ## +## Lavorare coi server remote ## -Per essere in grado di collaborare con un qualsiasi progetto Git, hai bisogno di sapere come amministrare il tuo repository remoto. I repository remoti sono versioni di progetti che sono ospitati in Internet o su una rete da qualche parte. Puoi averne più di uno, molti dei quali possono essere di sola lettura o di scrittura e lettura per te. Collaborare con altri implica di sapere amministrare questi repository remoti e mettere e togliere i dati a e da questi quando hai necessità di condividerli per lavoro. -Amministrare repository remoti include il sapere aggiungere repository remoti, rimuovere quelli che non sono validi, amministrare vari rami remoti e definire quando sono tracciati o meno, e altro. In questa sezione, vedremo le tecniche di amministrazione remota. +Per poter collaborare con un qualsiasi progetto Git, devi sapere come amministrare i tuoi repository remoti. I repository remoti sono versioni dei progetti ospitate da qualche parte su Internet o sulla rete locale. Puoi averne molti e normalmente avrai un accesso in sola lettura o anche in scrittura. Collaborare con altri implica di sapere amministrare questi repository remoti, inviarne e prelevarne dati per condividere il lavoro. +Amministrare i repository remoti significa sapere come aggiungerli, rimuovere quelli che non più validi, amministrare varie diramazioni remote e decidere quali tracciare e quali no, e ancora altro. Di seguito tratteremo le conoscenze necessarie per farlo. -### Visualizzare la Sorgente Remota ### +### Vedi i tuoi server remoti ### -Per vedere quale server remoto hai configurato, puoi lanciare il comando git remote. Questo elenca i soprannomi di ogni nodo specificato. Se hai clonato il tuo repository, dovresti al limite vedere origin — che è il nome predefinito che Git da al server che hai clonato: +Per vedere i server remoti che hai configurato, puoi eseguire il comando `git remote`. Questo elenca i nomi brevi di ogni nodo remoto che hai configurato. Se hai clonato il tuo repository, dovresti vedere almeno *origin* — che è il nome predefinito che Git da al server da cui cloni: $ git clone git://github.com/schacon/ticgit.git - Initialized empty Git repository in /private/tmp/ticgit/.git/ - remote: Counting objects: 595, done. - remote: Compressing objects: 100% (269/269), done. - remote: Total 595 (delta 255), reused 589 (delta 253) - Receiving objects: 100% (595/595), 73.31 KiB | 1 KiB/s, done. - Resolving deltas: 100% (255/255), done. + Cloning into 'ticgit'... + remote: Reusing existing pack: 1857, done. + remote: Total 1857 (delta 0), reused 0 (delta 0) + Receiving objects: 100% (1857/1857), 374.35 KiB | 193.00 KiB/s, done. + Resolving deltas: 100% (772/772), done. + Checking connectivity... done. $ cd ticgit $ git remote origin -Puoi anche specificare `-v`, che mostra l'URL che Git ha salvato per il soprannome: +Puoi anche aggiungere `-v`, che mostra anche l'URL che Git ha associato a quel nome breve: $ git remote -v origin git://github.com/schacon/ticgit.git (fetch) origin git://github.com/schacon/ticgit.git (push) -Se hai più di un repository remoto, il comando li elenca tutti. Per esempio, il mio repository Grit assomiglia a questo. +Se hai più di un server remoto, il comando li elenca tutti. Per esempio, il mio repository di Grit appare così: $ cd grit $ git remote -v @@ -772,11 +843,11 @@ Se hai più di un repository remoto, il comando li elenca tutti. Per esempio, il koke git://github.com/koke/grit.git origin git@github.com:mojombo/grit.git -Questo significa che possiamo prendere i contributi da qualsiasi di questi utenti in modo facile. Ma nota che solo origin è un URL SSH, è l'unico dove posso fare il push (vedremo questa cosa nel Capitolo 4). +Questo significa che posso prendere facilmente i contributi da qualunque di questi utenti. Nota però che solamente *origin* è un URL SSH, e quindi è l'unico dove posso inviare il mio lavoro con `push` (il perché lo vedremo nel *Capitolo 4*). -### Aggiungere un Repository Remoto ### +### Aggiungere un repository remoto ### -Ho menzionato e fornito alcune dimostrazioni, nelle sezioni precedenti, sull'aggiunta di repository remoti, ma qui scendo nello specifico. Per aggiungere un nuovo repository Git con un soprannome per riconoscerlo velocemente, avvia `git remote add [soprannome] [url]`: +Nelle sezioni precedenti ho accennato all'aggiunta dei repository remoti e dato alcuni esempi, ma qui lo vedremo nello specifico. Per aggiungere un nuovo repository Git remoto con un nome breve a cui possa riferirti facilmente, esegui `git remote add [nome breve] [url]`: $ git remote origin @@ -785,7 +856,7 @@ Ho menzionato e fornito alcune dimostrazioni, nelle sezioni precedenti, sull'agg origin git://github.com/schacon/ticgit.git pb git://github.com/paulboone/ticgit.git -Ora puoi usare la stringa pb dalla linea di comando al posto dell'intero URL. Per esempio, se vuoi prelevare tutte le informazioni che Paul ha ma che ancora non hai nel tuo repository, puoi lanciare git fetch pb: +Ora potrai usare il nome `pb` alla riga di comando al posto dell'URL intero. Se vuoi, per esempio, prendere tutto ciò che ha Paul, ma che non sono ancora nel tuo repository, puoi eseguire `git fetch pb`: $ git fetch pb remote: Counting objects: 58, done. @@ -796,31 +867,31 @@ Ora puoi usare la stringa pb dalla linea di comando al posto dell'intero URL. Pe * [new branch] master -> pb/master * [new branch] ticgit -> pb/ticgit -Il ramo master di Paul è accessibile localmente come `pb/master` — puoi unirlo in uno dei tuoi rami, o puoi caricare un tuo ramo locale a questo punto per ispezionarlo. +La diramazione `master` di Paul è accessibile localmente come `pb/master` — puoi farne il `merge` in uno delle tue diramazioni, o puoi scaricarla in una tua diramazione locale se vuoi controllarla. -### Prelevare e Trarre da Sorgenti in Remoto ### +### Scarica e condividi coi server remoti ### -Come già visto, per ottenere i dati da un progetto remoto, puoi farlo: +Come abbiamo appena visto, per scaricare dati da un progetto remoto, puoi fare: $ git fetch [nome-remoto] -Il comando va sul progetto remoto e si tira giù tutti i dati dal progetto remoto che ancora non hai. Dopo aver fatto questo, dovresti avere tutti i riferimenti ai rami da questa sorgente remota, che poi potrai fondere o ispezionare in ogni momento. (Vedremo cosa sono i rami e come usarli in maggior dettaglio al *Capitolo 3*). +Il comando va sul progetto remoto e scarica tutti i dati dal progetto remoto che tu ancora non hai. Dopo averlo fatto dovresti trovare i riferimenti a tutte le diramazioni di quel server, che potrai unire o controllare in qualsiasi momento. (Vedremo in dettaglio cosa sono le diramazioni e come usarle nel *Capitolo 3*). -Se hai clonato un repository, il comando automaticamente aggiunge un repository remoto sotto il nome origin. Così, `git fetch origin` preleva ogni lavoro che è stato inserito su quel server da quando hai fatto la clonazione (o dall'ultimo prelievo). E' importante notare che il comando `fetch` mette i dati nel tuo repository locale — non unisce automaticamente e non modifica alcun file su cui tu stai lavorando. Devi eseguire la fusione manualmente nel tuo lavoro, quando sei pronto. +Quando cloni un repository, viene aggiunto automaticamente un repository remoto chiamato *origin*. In questo modo `git fetch origin` scarica le modifiche che sono state condividise con server remoto da quando lo hai clonato (o dall'ultimo tuo aggiornamento). È importante notare che il comando `fetch` scarica queste informazioni nel tuo repository locale: non le unisce automaticamente e non modifica alcun file su cui stai lavorando. Quando sei pronto dovrai essere tu a unirle al tuo lavoro, manualmente. -Se hai un ramo impostato per tracciare un ramo remoto (vedi la prossima sezione e il Capitolo 3 per maggiori informazioni), puoi usare il comando `git pull` per prelevare automaticamente e poi fondere un ramo remoto nel ramo corrente. Questo è un modo più facile e comodo di lavorare; e in modo predefinito, il comando `git clone` automaticamente imposta il tuo ramo locale master per tracciare il ramo remoto master del server che hai clonato (assumendo che il sorgente remoto abbia un ramo master). Lanciare `git pull` generalmente preleva i dati dal server di origine clonato e automaticamente prova a fondere il codice con il codice su cui stai lavorando. +Se hai una diramazione impostata per tracciarne una remota (vedi la prossima sezione e il *Capitolo 3* per maggiori informazioni), puoi usare il comando `git pull` per scaricare e unire automaticamente una diramazione remota in quella attuale. Questo potrebbe essere un modo più facile e più comodo per lavorare; e in modo predefinito, il comando `git clone` imposta automaticamente la tua diramazione `master` per tracciare il master del server che hai clonato (supponendo che il server remoto abbia una diramazione `master`). Eseguendo `git pull` vengono generalmente scaricati i dati dal server da cui hai fatto il clone originario e prova a unirli automaticamente con il codice su cui stai lavorando. -### Inserire nella Sorgente Remota ### +### Condividi coi server remoti ### -Quando hai il tuo progetto al punto in cui lo vuoi condividere, devi inviarlo a monte (push upstream). Il comando per fare questo è semplice: `git push [nome-remoto] [nome-ramo]`. Se vuoi fare il push del tuo ramo master al tuo server `origin` (ancora, generalmente con la clonazione sono impostati entrambi questi nomi automaticamente), puoi lanciare il push per mettere il tuo lavoro sul server: +Quando il tuo progetto raggiunge uno stato che vuoi condividere, devi caricarlo sul server principale. Il comando perlo è semplice: `git push [nome-remoto] [diramazione]`. Se vuoi condividere la tua diramazione `master` sul tuo server `origin` (lo ripeto: clonando questi nomi vengono generalmente definiti automaticamente), puoi eseguire il comando seguente per caricare il tuo lavoro sul server: $ git push origin master -Questo comando funziona solamente se hai fatto una clonazione da un server in cui hai i permessi di scrittura e se nessuno ha inviato dati nel mentre. Se tu e qualcun altro clonate un repository nello stesso momento ed essi inviano i dati, e poi tu invii i dati, il tuo invio verrà gustamente rifiutato. Devi prima scaricare il loro lavoro ed incorporarlo nel tuo per poter inviare le tue modifiche. Vedi il *Capitolo 3* per maggiori dettagli ed informazioni su come fare il push su server remoti. +Questo comando funziona solamente se hai clonato il tuo progetto da un server su cui hai i permessi di scrittura e se nessun altro ha caricato modifiche nel frattempo. Se cloni un repository assieme ad altri e questi caricano delle modifiche sul server, il tuo invio verrà rifiutato. Dovrai prima scaricare le loro modifiche e incorporarle con le tue per poterle poi inviare. Vedi il *Capitolo 3* per maggiori informazioni su come fare il `push` su server remoti. -### Ispezionare una Sorgente Remota ### +### Controllare un server remoto ### -Se vuoi vedere più informazioni su di una sorgente remota in particolare, puoi usare il comando `git remote show [nome-remoto]`. Se lanci il comando con un soprannome particolare, come `origin`, avrai qualcosa di simile a questo: +Se vuoi più informazioni su una particolare server remoto, puoi usare il comando `git remote show [nome-remoto]`. Se esegui il comando con un nome particolare, per esempio `origin`, avrai qualcosa di simile: $ git remote show origin * remote origin @@ -831,9 +902,9 @@ Se vuoi vedere più informazioni su di una sorgente remota in particolare, puoi master ticgit -Questo elenca tutti gli URL del repository remoto oltre che alle informazioni sui rami tracciati. Il comando utilmente ti dirà che sei sul ramo principale e se lanci `git pull`, questo automaticamente unirà il ramo master sul server remoto dopo aver prelevato tutte i riferimenti remoti. Inoltre elencherà i riferimenti che ha scaricato. +che mostra gli URL del repository remoto oltre alle informazioni sulle diramazioni tracciate. Il comando ti dice anche se esegui `git pull` mentre sei su `master`, integrerà le modifiche sul `master` remoto dopo aver scaricato tutti i riferimenti remoti. Elenca anche i riferimenti remoti che hai già scaricato. -Questo è un semplice esempio che potrai incontrare. Quando usi moltissimo Git, tuttavia, potrai vedere molte più informazioni da `git remote show`: +Questo è un esempio semplice di quanto probabilmente vedrai. Tuttavia, quando usi intensamente Git potresti trovare molte più informazioni con `git remote show`: $ git remote show origin * remote origin @@ -857,20 +928,20 @@ Questo è un semplice esempio che potrai incontrare. Quando usi moltissimo Git, Local branch pushed with 'git push' master:master -Questo comando mostra quale ramo è automaticamente caricato quando lanci `git push` su certe diramazioni. Inoltre ti mostrerà quali rami remoti sul server che ancora non possiedi, quali rami remoti possiedi e che saranno rimossi dal server, e le diramazioni che saranno automaticamente unite quando lancerai `git pull`. +Questo comando mostra quale diramazione viene scaricata automaticamente quando esegui `git push` su certe diramazioni. Mostra anche quali diramazioni remote non hai ancora scaricato, quali diramazioni remote hai in locale che sono state rimosse dal server, e le diramazioni che vengono unite automaticamente quando esegui `git pull`. -### Rimuovere e Rinominare Sorgenti Remote ### +### Rimuovere e rinominare server remoti ### -Se vuoi rinominare un riferimento, nelle nuove versioni di Git, puoi lanciare `git remote rename` per cambiare il soprannome di una sorgente remota. Per esempio, se vuoi rinominare `pb` in `paul`, puoi farlo con `git remote rename`: +Se vuoi rinominare un riferimento, con versioni più recenti di Git, puoi farlo con `git remote rename` per cambiare il nome breve di un server remoto. Se vuoi per esempio rinominare `pb` in `paul`, puoi farlo con `git remote rename`: $ git remote rename pb paul $ git remote origin paul -Vale la pena ricordare che questo cambia anche i nomi dei rami remoti. Quello che prima era riferito a `pb/master` ora è `paul/master`. +Vale la pena ricordare che questo cambia anche i nomi delle diramazioni remote. Quello che prima veniva chiamato `pb/master` ora è `paul/master`. -Se vuoi rimuovere un riferimento per una qualche ragione — hai spostato il server o non stai più usando un mirror particolare, o magari un collaboratore non collabora più — puoi usare `git remote rm`: +Se vuoi rimuovere un riferimento per qualsiasi ragione (hai spostato il server o non stai più usando un particolare mirror, o magari un collaboratore che non collabora più) puoi usare `git remote rm`: $ git remote rm paul $ git remote @@ -878,19 +949,19 @@ Se vuoi rimuovere un riferimento per una qualche ragione — hai spostato il ser ### Etichettare ### -Come la maggior parte dei VCS, Git ha la possibilità di contrassegnare (tag, ndt) dei punti specifici della storia come importanti. Generalmente, le persone usano questa funzionalità per marcare i punti di rilascio (v1.0, e così via). In questa sezione, imparerai come elencare le etichette disponibili, come crearne di nuove, ed i differenti tipi di etichette esistenti. +Come la maggior parte dei VCS, Git ha la possibilità di contrassegnare (tag, ndt) dei punti specifici della cronologia come importanti. Le persone normalmente usano questa funzionalità per segnare i punti di rilascio (v1.0, e così via). In questa sezione, imparerai come elencare le etichette disponibili, come crearne di nuove, e i diversi tipi di etichette esistenti. -### Elencare le Proprie Etichette ### +### Elena le etichette ### -Elencare le etichette disponibili in Git è facilissimo. Semplicemente digita `git tag`: +Elencare le etichette esistenti in Git è facilissimo. Digita semplicemente `git tag`: $ git tag v0.1 v1.3 -Questo comando elenca le etichette in ordine alfabetico; l'ordine con il quale compaiono non è realmente importante. +Questo comando elenca le etichette in ordine alfabetico; l'ordine con cui appaiono non ha importanza. -Puoi inoltre cercare le etichette con uno schema specifico. Il repository sorgente di Git, per esempio, contiene più di 240 etichette. Se sei solo interessato a vedere quelli della serie 1.4.2, puoi lanciare: +Puoi inoltre cercare etichette con uno schema specifico. Il repository sorgente di Git, per esempio, contiene più di 240 etichette. Se sei interessato a vedere solo quelli della serie 1.4.2, puoi eseguire: $ git tag -l 'v1.4.2.*' v1.4.2.1 @@ -898,13 +969,13 @@ Puoi inoltre cercare le etichette con uno schema specifico. Il repository sorgen v1.4.2.3 v1.4.2.4 -### Creare Etichette ### +### Creare etichette ### -Git usa due principali tipi di etichette: lightweight (semplificate, ndt) e annotated (commentate, ndt). Un'etichetta lightweight è molto simile ad un ramo che non è cambiato — è semplicemente un riferimento ad uno specifico commit. Le etichette annotated, tuttavia, sono salvate come oggetti nel database Git. Ne viene calcolato il checksum; contengono il nome, l'e-mail e la data di chi ha inserito l'etichetta; hanno un messaggio; e possono essere firmati e verificati con GNU Privacy Guard (GPG). É generalmente raccomandato creare etichette annotated così puoi avere tutte queste informazioni; ma se vuoi temporaneamente inserire un'etichetta e per qualche ragione non vuoi avere queste informazioni, le etichette lightweight sono ancora disponibili. +Git ha due tipi di etichette: semplici (`lightweight`, ndt) e annotate (`annotated`, ndt). Un'etichetta semplice è molto simile a una ramificazione che non cambia mai: è semplicemente un riferimento ad una commit specifica. Le etichette annotate, al contrario, sono salvate come oggetti complessi nel database Git. Ne viene calcolato il checksum, contengono il nome, l'e-mail e la data di chi ha inserito l'etichetta, hanno un messaggio d'etichetta; e possono essere firmate e verificate con GPG (GNU Privacy Guard). Generalmente si raccomanda di usare le etichette annotate così da avere tutte queste informazioni, ma se vuoi aggiungere un'etichetta temporanea o per qualche ragione non vuoi salvare quelle informazioni aggiuntive, hai sempre a disposizione le etichette semplici. -### Etichette Annotated ### +### Etichette annotate ### -Creare un'etichetta annotated in Git è semplice. La via più facile è specificare `-a` quando si lancia il comando `tag`: +Creare un'etichetta annotate in Git è semplice. Il modo più facile è specificare `-a` quando esegui il comando `tag`: $ git tag -a v1.4 -m 'my version 1.4' $ git tag @@ -912,9 +983,9 @@ Creare un'etichetta annotated in Git è semplice. La via più facile è specific v1.3 v1.4 -`-m` specifica il messaggio, che è salvato con l'etichetta. Se non specifichi un messaggio per una etichetta annotated, Git lancerà il tuo editor così potrai inserirlo. +`-m` specifica il messaggio per l'etichetta, che viene salvato con la stessa. Se non specifichi un messaggio per un'etichetta annotata, Git lancerà il tuo editor così da scriverla. -Puoi vedere i dati dell'etichetta assieme al commit in cui è stato inserito l'etichetta con il comando `git show`: +Puoi vedere i dati dell'etichetta assieme alla commit etichettata con il comando `git show`: $ git show v1.4 tag v1.4 @@ -929,18 +1000,18 @@ Puoi vedere i dati dell'etichetta assieme al commit in cui è stato inserito l'e Merge branch 'experiment' -Questo mostra le informazioni di chi ha eseguito l'etichetta, la data del commit della stessa, ed il messaggio prima di mostrare le informazioni del commit. +Questo mostra le informazioni dell'etichetta, la data in cui la commit è stata etichettata e il messaggio, prima di mostrare le informazioni della commit. -### Firmare le Etichette ### +### Etichette firmate ### -Puoi anche firmare le tue etichette con GPG, assumendo che tu abbia una chiave privata. Tutto quello che devi fare è usare `-s` invece di `-a`: +Puoi anche firmare le tue etichette con GPG, presumendo che tu abbia una chiave privata. Tutto quello che devi fare è usare `-s` invece di `-a`: $ git tag -s v1.5 -m 'my signed 1.5 tag' You need a passphrase to unlock the secret key for user: "Scott Chacon " 1024-bit DSA key, ID F721C45A, created 2009-02-09 -Se lanci `git show` su questa etichetta, potrai vedere la tua firma GPG in allegato ad essa: +Se esegui `git show` per questa etichetta, puoi vedere che è stata allegata la tua firma GPG: $ git show v1.5 tag v1.5 @@ -964,9 +1035,9 @@ Se lanci `git show` su questa etichetta, potrai vedere la tua firma GPG in alleg Più avanti, imparerai come verificare le etichette firmate. -### Etichette Lightweight ### +### Etichette semplici ### -Un altro modo per marcare i commit è usare le etichette lightweight. Questo è semplicemente fare il checksum del commit salvato in un file — nessun'altra informazione è mantenuta. Per creare un'etichetta semplificata, non fornire l'opzione `-a`, `s` o `-m`: +Un altro modo per etichettare una commit è con le etichette semplici. Questo in pratica è salvare il checksum della commit in un file: non viene salvata nessun'altra informazione. Per creare un'etichetta semplice, non usare le opzioni `-a`, `s` o `-m`: $ git tag v1.4-lw $ git tag @@ -976,7 +1047,7 @@ Un altro modo per marcare i commit è usare le etichette lightweight. Questo è v1.4-lw v1.5 -A questo punto, se lanci `git show` sulla tua etichetta, non vedrai altre informazioni aggiuntive. Il comando semplicemente mostra il commit: +Se ora lanci `git show` per questa etichetta, non vedrai altre informazioni aggiuntive. Il comando mostra solamente la commit: $ git show v1.4-lw commit 15027957951b64cf874c3557a0f3547bd83b3ff6 @@ -986,9 +1057,9 @@ A questo punto, se lanci `git show` sulla tua etichetta, non vedrai altre inform Merge branch 'experiment' -### Verificare le Etichette ### +### Verificare le etichette ### -Per verificarele etichetta firmate, usa `git tag -v [nome-tag]`. Questo comando usa la verifica GPG della firma. Avrai bisogno della chiave pubblica del firmatario nel tuo portachiavi affinché funzioni correttamente: +Per verificare un'etichetta firmata, usa `git tag -v [nome-tag]`. Questo comando usa GPG per verificare la verifica. Affinché funzioni hai bisogno che la chiave pubblica del firmatario sia nel tuo portachiavi: $ git tag -v v1.4.2.1 object 883653babd8ee7ea23e6a5c392bb739348b1eb61 @@ -1004,15 +1075,15 @@ Per verificarele etichetta firmate, usa `git tag -v [nome-tag]`. Questo comando gpg: aka "[jpeg image of size 1513]" Primary key fingerprint: 3565 2A26 2040 E066 C9A7 4A7D C0C6 D9A4 F311 9B9A -Se non hai la chiave pubblica del firmatario, otterrai qualche cosa di simile a questo invece: +Se non hai la chiave pubblica del firmatario, otterrai invece qualcosa così: gpg: Signature made Wed Sep 13 02:08:25 2006 PDT using DSA key ID F3119B9A gpg: Can't check signature: public key not found error: could not verify the tag 'v1.4.2.1' -### Inserire una Etichetta Successivamente ### +### Etichettare successivamente ### -Puoi anche etichettare i commit che hai già superato. Supponiamo che la storia dei tuoi commit sia come questa: +Puoi etichettare anche commit passate. Supponiamo che la cronologia delle tue commit sia questa: $ git log --pretty=oneline 15027957951b64cf874c3557a0f3547bd83b3ff6 Merge branch 'experiment' @@ -1026,11 +1097,11 @@ Puoi anche etichettare i commit che hai già superato. Supponiamo che la storia 964f16d36dfccde844893cac5b347e7b3d44abbc commit the todo 8a5cbc430f1a9c3d00faaeffd07798508422908a updated readme -Ora, supponiamo che ti sia dimenticato di mettere l'etichetta v1.2 al tuo progetto, che è al commit "updated rakefile". Puoi aggiungerlo successivamente. Per marcare questo commit, devi specificare il checksum (o parte di esso) del commit alla fine del comando: +Supponiamo che abbia dimenticato di etichettare il progetto alla `v1.2`, che era con la commit "updated rakefile". Puoi sempre aggiungerla in un secondo momento. Per etichettare questa commit, alla fine del comando, devi indicare il checksum (o parte di esso) della commit: - $ git tag -a v1.2 9fceb02 + $ git tag -a v1.2 -m 'version 1.2' 9fceb02 -Puoi vedere che hai marcato il commit: +Puoi vedere che hai etichettato la commit: $ git tag v0.1 @@ -1053,9 +1124,9 @@ Puoi vedere che hai marcato il commit: updated rakefile ... -### Condividere le Etichette ### +### Condividere le etichette ### -Di base, il comando `git push` non trasferisce le etichette sui server remoti. Devi esplicitamente inviare le etichette da condividere con il server dopo averle create. Questo processo è come condividere rami remoti — puoi lanciare `git push origin [nometag]`. +Normalmente il comando `git push` non invia le etichette sui server remoti. Devi farlo esplicitamente, dopo averle create, per condividerle con il server. Questo procedimento è come la condivisione delle diramazioni remote: puoi eseguire `git push origin [nome-tag]` $ git push origin v1.5 Counting objects: 50, done. @@ -1065,7 +1136,7 @@ Di base, il comando `git push` non trasferisce le etichette sui server remoti. D To git@github.com:schacon/simplegit.git * [new tag] v1.5 -> v1.5 -Se hai molte etichetta che vuoi inviare tutte assieme, puoi farlo usando l'opzione `--tags` del comando `git push`. Questo trasferirà tutti le tue etichette sul server remoto che non sono ancora presenti. +Se hai molte etichetta che vuoi inviare tutte assieme, puoi farlo usando l'opzione `--tags` col comando `git push`. Questo trasferirà al server remoto tutte le tue etichette che non sono ancora presenti. $ git push origin --tags Counting objects: 50, done. @@ -1079,61 +1150,64 @@ Se hai molte etichetta che vuoi inviare tutte assieme, puoi farlo usando l'opzio * [new tag] v1.4-lw -> v1.4-lw * [new tag] v1.5 -> v1.5 -Ora, quando qualcun altro clona o scarica dal tuo repository, avrà anche tutti le tue etichette. +Quando qualcuno clonerà il repository o scaricherà gli aggiornamenti, scaricherà anche tutte le tue etichette. -## Suggerimenti e Trucchi ## +## Suggerimenti ## -Prima di finire questo capitolo sulle basi di Git, ecco alcuni suggerimenti e trucchi per rendere l'esperienza nell'uso di Git più semplice, facile e familiare. Molte persone usano Git senza usare questi suggerimenti e non ci riferiremo ad essi o presumeremo che tu li abbia usati successivamente nel libro; ma probabilmente dovresti sapere come realizzarli. +Prima di terminare questo capitolo sulle basi di Git, ecco alcuni suggerimenti e trucchi per rendere la tua esperienza con Git più semplice, più facile e più familiare. Molte persone usano Git ma nessuno di questi suggerimenti e in seguito nel libro non ci riferiremo ad essi né presumeremo che tu li abbia usati, ma probabilmente dovresti sapere come realizzarli. -### Auto-Completamento ### +### Completamento automatico ### -Se usi una shell Bash, Git fornisce un piacevole script di auto completamento che può essere usato. Scarica il codice sorgente di Git, e guarda nella directory `contrib/completation`; dovrebbe esserci un file chiamato `git-completation.bash`. Copia questo file nella tua directory di home e aggiungila al tuo file `.bashrc`: +Se usi una shell Bash, Git fornisce uno script carino per il completamento automatico che potresti usare. Scaricalo direttamente dai sorgenti di Git su https://github.com/git/git/blob/master/contrib/completion/git-completion.bash. Copia questo file nella tua directory `home` e al tuo file `.bashrc` aggiungi: source ~/.git-completion.bash -Se vuoi impostare Git per avere l'auto completamento della shell Bash per tutti gli utenti, copia lo script nella directory `/opt/local/etc/bash_completion.d` sui sistemi Mac o in `/etc/bash_completion.d/` sui sistemi Linux. Questa è una directory degli script che Bash automaticamente carica per fornire l'auto completamento da shell. +Se vuoi che Git usi il completamento automatico in Bash per tutti gli utenti, copia lo script nella directory `/opt/local/etc/bash_completion.d` sui sistemi Mac o in `/etc/bash_completion.d/` sui sistemi Linux. Questa è una directory di script che Bash carica automaticamente, per fornire il completamento automatico nella shell. -Se stai usando Windows con Git Bash, che è l'installazione di base per Git su Windows con msysGit, l'auto completamento dovrebbe essere preconfigurato. +Se stai usando Windows con Git Bash, che è il predefinito quando installi Git su Windows con msysGit, il completamento automatico dovrebbe essere preconfigurato. -Premi il tasto Tab quando stai scrivendo un comando Git, e dovresti avere una serie di suggerimenti da selezionare: +Premi il tasto Tab quando stai scrivendo un comando Git, e dovresti vedere una serie di suggerimenti tra cui scegliere: $ git co commit config -In questo caso, scrivendo git co e poi premendo il tasto Tab due volte compaiono i suggerimenti commit e config. Aggiungendo `m` si completa `git commit` automaticamente. +In questo caso, scrivendo `git co` e premendo poi due volte il tasto Tab, compaiono i suggerimenti commit e config. Aggiungendo `m` automaticamente si completa `git commit`. -Questo funziona anche con le opzioni, cosa che forse è molto più utile. Per esempio, se si lancia il comando `git log` e non si ricorda una opzione, si può iniziare a pigiare il tasto Tab per vedere le corrispondenze: +Questo funziona anche con le opzioni, che probabilmente è molto più utile. Se per esempio stai eseguendo `git log` e non ricordi un'opzione, puoi premere il tasto Tab per vedere quelle disponibili: - $ git log --s - --shortstat --since= --src-prefix= --stat --summary + $ git log --s + --shortstat --sparse + --simplify-by-decoration --src-prefix= + --simplify-merges --stat + --since= --summary -Questo è un trucco davvero utile e permette di risparmiare molto tempo e lettura della documentazione. +Questo è un trucco davvero utile e permette di risparmiare molto tempo e evitarti la lettura della documentazione. -### Alias con Git ### +### Alias di Git ### -Git non deduce il comando se si digita solo in parte. Se non si vuole scrivere l'intero testo di qualsiasi comando Git, puoi facilmente scegliere un alias per ogni comando, usando `git config`. Qui ci sono un po' di esempi su alcune configurazioni che potresti volere impostare: +Git non indovina il tuo comando se ne digiti solo una parte. Se non vuoi vuole scrivere tutto il testo di un qualsiasi comando Git puoi configurare facilmente un alias per ogni comando usando `git config`. Di seguito ci sono alcuni esempi che potresti voler usare: $ git config --global alias.co checkout $ git config --global alias.br branch $ git config --global alias.ci commit $ git config --global alias.st status -Questo significa che, per esempio, invece di digitare `git commit`, hai solamente bisogno di scrivere `git ci`. Andando avanti con l'uso di Git, probabilmente ci saranno altri comandi che userai di frequente; in questi casi, non esitare a creare nuovi alias. +Questo significa che, per esempio, invece di digitare `git commit`, dovrai scrivere solo `git ci`. Andando avanti con l'uso di Git userai alcuni comandi con maggiore frequenza: e in questi casi non esitare a creare nuovi alias. -Questa tecnica può anche essere molto utile per creare comandi che ritieni dovrebbero esistere. Per esempio, per correggere un problema comune in cui si incorre quando si vuole disimpegnare un file dall'area di stage, puoi aggiungere il tuo alias unstage a Git: +Questa tecnica può essere anche molto utile per creare comandi che ritieni dovrebbero esistere. Per esempio, per correggere un problema comune in cui si incorre quando si vuole rimuovere un file dall'area di stage, puoi aggiungere il tuo alias `unstage` in Git: $ git config --global alias.unstage 'reset HEAD --' -Questo rende i seguenti due comandi equivalenti: +Questo rende equivalenti i due comandi seguenti: $ git unstage fileA $ git reset HEAD fileA -Questo sembra più pulito. É anche comodo aggiungere il comando `last`, come: +Questo sembra più pulito. É anche comodo aggiungere il comando `last`, così: $ git config --global alias.last 'log -1 HEAD' -In questo modo puoi vedere l'ultimo commit facilmente: +In questo modo puoi vedere facilmente l'ultima commit: $ git last commit 66938dae3329c7aebe598c2246a8e6af90d04646 @@ -1144,10 +1218,10 @@ In questo modo puoi vedere l'ultimo commit facilmente: Signed-off-by: Scott Chacon -Git semplicemente sostituisce il nuovo comando con quello che corrisponde all'alias. Magari, vuoi avviare un comando esterno, invece dei sotto comandi Git. In questo caso, devi avviare il comando con il carattere "!". Questo è utile se stai scrivendo i tuoi strumenti di lavoro con un repository Git. Per esempio creiamo un alias `git visual` per lanciare `gitk`: +Come immaginerai, Git semplicemente sostituisce il nuovo comando con qualsiasi cosa corrisponda all'alias. Potresti anche voler eseguire un comando esterno, piuttosto che uno di Git. In questo caso devi iniziare il comando con un "!". Questo è utile se stai scrivendo degli strumenti di lavoro tuoi per lavorare con un repository Git. Vediamolo praticamente creando l'alias `git visual` per eseguire `gitk`: $ git config --global alias.visual '!gitk' -## Riassunto ## +## Sommario ## -A questo punto, sei in grado di fare tutte le operazioni di Git base in locale — creare o clonare un repository, fare delle modifiche, parcheggiare ed inviare queste modifiche, vedere la storia di tutti i cambiamenti del repository fatti. Nel prossimo capitolo, vedremo una caratteristica vincente di Git: il suo modello di ramificazione. +A questo punto, sei in grado di eseguire tutte le operazioni di base di Git in locale: creare o clonare un repository, fare delle modifiche, mettere nello `stage` e inviare queste modifiche, vedere la cronologia delle modifiche fatte al repository. Nel prossimo capitolo, vedremo la caratteristica vincente di Git: il suo modello di ramificazione. diff --git a/it/03-git-branching/01-chapter3.markdown b/it/03-git-branching/01-chapter3.markdown index 50f2b7293..6f3ff1dbc 100644 --- a/it/03-git-branching/01-chapter3.markdown +++ b/it/03-git-branching/01-chapter3.markdown @@ -71,7 +71,7 @@ Questo è interessante, perché ora il tuo ramo testing è stato spostato in ava La Figura 3-8 mostra il risultato. -insert 18333fig0308.png +Insert 18333fig0308.png Figura 3-8. HEAD si è spostato ad un altro ramo con un checkout. Questo comando ha fatto due cose. Ha spostato il puntatore HEAD indietro per puntare al ramo master e ha riportato i file nella tua directory di lavoro allo stato in cui si trovavano in quel momento. Questo significa anche che i cambiamenti che farai da questo punto in poi saranno separati da una versione più vecchia del progetto. Essenzialmente riavvolge temporaneamente il lavoro che hai fatto nel tuo ramo testing così puoi muoverti in una direzione differente. @@ -268,7 +268,7 @@ Se vuoi usare uno strumento grafico per risolvere i problemi, puoi lanciare `git {remote}: modified Hit return to start merge resolution tool (opendiff): -Se vuoi usare uno strumento di fusione differente dal predefinito (Git usa `opendiff` in questo caso perché ho lanciato il comando su un Mac), puoi vedere tutti gli strumenti supportati all'inizio dopo “merge tool candidates”. Scrivi il nome dello strumento che vorresti usare. Nel Capitolo 7, discuteremo su come puoi modificare i valori predefiniti del tuo ambiente. +Se vuoi usare uno strumento di fusione differente dal predefinito (Git usa `opendiff` in questo caso perché ho lanciato il comando su un Mac), puoi vedere tutti gli strumenti supportati all'inizio dopo “... one of the following tools:” (uno dei seguenti strumenti, ndt.). Scrivi il nome dello strumento che vorresti usare. Nel Capitolo 7, discuteremo su come puoi modificare i valori predefiniti del tuo ambiente. Dopo che sei uscito dallo strumento di fusione, Git ti chiederà se la fusione è avvenuta con successo. Se gli dirai allo script che è così, parcheggerà i file in modo da segnarli come risolti per te. @@ -388,7 +388,7 @@ Questo può un po' confondere, quindi vediamo un esempio. Diciamo che hai un ser Insert 18333fig0322.png Figura 3-22. Un clone con Git fornisce un proprio ramo principale e un puntatore origin/master al ramo principale di origine. -Se fai del lavoro sul tuo ramo principale locale, e, allo stesso temo, qualcuno ha inviato degli aggiornamenti al ramo principale di `git.ourcompany.com`, allora la tua storia si muoverà in avanti in modo differente. Inoltre, mentre non hai contatti con il tuo server di partenza, il tuo puntatore `origin/master` non si sposterà (vedi Figura 3-23). +Se fai del lavoro sul tuo ramo principale locale, e, allo stesso tempo, qualcuno ha inviato degli aggiornamenti al ramo principale di `git.ourcompany.com`, allora la tua storia si muoverà in avanti in modo differente. Inoltre, mentre non hai contatti con il tuo server di partenza, il tuo puntatore `origin/master` non si sposterà (vedi Figura 3-23). Insert 18333fig0323.png Figura 3-23. Lavorando in locale ed avendo qualcuno che ha inviato al server remoto qualcosa rende l'avanzamento delle storie differente. diff --git a/it/04-git-server/01-chapter4.markdown b/it/04-git-server/01-chapter4.markdown index af62c8b8a..514cd51f0 100644 --- a/it/04-git-server/01-chapter4.markdown +++ b/it/04-git-server/01-chapter4.markdown @@ -70,7 +70,7 @@ L'aspetto negativo di SSH è che non puoi dare accesso anonimo al tuo repository ### Il Protocollo Git ### -Poi c'è il protocollo Git. Questo è un demone speciale che è incluso nel pacchetto Git; è in ascolto su una porta dedicata (9418) e fornisce un servizio simile al protocollo SSH, ma assolutamente senza autenticazione. Per permettere ad un repository di essere servito tramite il protocollo Git, devi creare un file `git-export-daemon-ok` — il demone non serve il repository senza l'inserimento di questo file — altrimenti non ci sarebbe sicurezza. O il repository Git è disponibile per chiunque voglia copiarlo o altrimenti niente. Questo significa che generalmente non si invia tramite questo protocollo. Puoi abilitare l'accesso all'invio; ma data la mancanza di autenticazione, se abiliti l'accesso di scrittura, chiunque trovi su internet l'URL al progetto può inviare dati. Basti dire che questo è raro. +Poi c'è il protocollo Git. Questo è un demone speciale che è incluso nel pacchetto Git; è in ascolto su una porta dedicata (9418) e fornisce un servizio simile al protocollo SSH, ma assolutamente senza autenticazione. Per permettere ad un repository di essere servito tramite il protocollo Git, devi creare un file `git-daemon-export-ok` — il demone non serve il repository senza l'inserimento di questo file — altrimenti non ci sarebbe sicurezza. O il repository Git è disponibile per chiunque voglia copiarlo o altrimenti niente. Questo significa che generalmente non si invia tramite questo protocollo. Puoi abilitare l'accesso all'invio; ma data la mancanza di autenticazione, se abiliti l'accesso di scrittura, chiunque trovi su internet l'URL al progetto può inviare dati. Basti dire che questo è raro. #### I Pro #### @@ -111,15 +111,16 @@ Un'altra cosa carina è che l'HTTP è un protocollo comunissimo che i firewall d L'altra faccia della medaglia nel fornire il tuo repository via HTTP è che è relativamente inefficiente per il client. In genere porta via molto tempo per clonare o scaricare dal repository, e si ha spesso un sovraccarico della rete tramite il trasferimento di volumi via HTTP rispetto ad altri protocolli di rete. Non essendo abbastanza intelligente da trasferire solo i dati di cui hai bisogno — non c'è un lavoro dinamico dalla parte del server in questa transazione — il protocollo HTTP viene spesso definito un protocollo _stupido_. Per maggiori informazioni sulle differenze nell'efficienza tra il protocollo HTTP e gli altri, vedi il Capitolo 9. -## Ottenere Git su di un Server ## +## Mettere Git su di un server ## Per inizializzare un qualsiasi server Git, devi esportare un repository esistente in un nuovo repository di soli dati — cioè un repository che non contiene la directory di lavoro. Questo è generalmente molto semplice da fare. Per clonare il tuo repository per creare un nuovo repository di soli dati, devi avviare il comando clone con l'opzione `--bare`. Convenzionalmente, un repository di soli dati in finisce in `.git`, ad esempio: $ git clone --bare my_project my_project.git - Initialized empty Git repository in /opt/projects/my_project.git/ + Cloning into bare repository 'my_project.git'... + done. -L'output di questo comando confonde un pochino. Dato che `clone` è un `git init` quindi un `git fetch`, vediamo parte dell'output dalla parte `git init`, il quale crea una directory vuota. L'effecttivo trasferimento dell'oggetto non fornisce output, ma avviene. Ora dovresti avere una copia della directory dei dati di Git nella directory `my_project.git`. +Ora dovresti avere una copia della directory dei dati di Git nella directory `my_project.git`. La stessa cosa la si può ottenere con @@ -226,14 +227,18 @@ Devi solo aggiungerle al tuo file `authorized_keys`: $ cat /tmp/id_rsa.josie.pub >> ~/.ssh/authorized_keys $ cat /tmp/id_rsa.jessica.pub >> ~/.ssh/authorized_keys -Ora, puoi impostare un repository vuoto avviando `git init` con l'opzione `--bare`, che inizializza il repository senza la directory di lavoro: +L'autenticazione tramite chiavi SSH generalmente richiede una restrizione dei diritti di accesso ai file coinvolti. Per prevenire qualsiasi problema è necessario eseguire: + + $ chmod -R go= ~/.ssh + +Ora, puoi configurargli un repository vuoto eseguendo `git init` con l'opzione `--bare`, che inizializza il repository senza la directory di lavoro: $ cd /opt/git $ mkdir project.git $ cd project.git $ git --bare init -Poi, John, Josie o Jessica possono inviare la prima versione del loro progetto nel repository aggiungendolo come ramo remoto ed inviandolo su di un ramo. Nota che qualcuno deve accedere via shell alla macchina e creare un repository base ogni volta che si vuole aggiungere un progetto. Usiamo il nome `gitserver` per il server dove hai impostato il tuo utente 'git' ed il repository. Se lo stai usando nella rete interna e hai impostato un DNS con il punto `gitserver` per puntare a questo server, allora puoi usare il comando: +E John, Josie o Jessica possono inviare la prima versione del loro progetto nel repository aggiungendolo come ramo remoto ed inviandolo su di un ramo. Fai attenzione che ogni volta che vuoi aggiungere un progetto, qualcuno deve accedere via shell alla macchina e creare un repository base. Usiamo il nome `gitserver` per il server dove hai impostato il tuo utente 'git' ed il repository. Se lo stai usando nella rete interna e hai impostato un DNS con il punto `gitserver` per puntare a questo server, allora puoi usare il comando: # sul computer di Johns $ cd myproject @@ -368,7 +373,7 @@ Gitosis richiede alcuni strumenti Python, così prima devi installare il pacchet Poi, puoi clonare ed installare Gitosis dal progetto principale: - $ git clone git://eagain.net/gitosis.git + $ git clone https://github.com/tv42/gitosis.git $ cd gitosis $ sudo python setup.py install @@ -716,7 +721,7 @@ Puoi controllare quali progetti GitWeb lascia sfogliare agli utenti via browser Ora, se fai il commit ed il push del progetto, GitWeb automaticamente inizierà a mostrare il progetto iphone. -## Hosted Git ## +## Hosting Git ## Se non vuoi svolgere tutto il lavoro di configurazione di un tuo server Git, hai varie opzioni per ospitare i tuoi progetti Git su un sito esterno e dedicato. Fare questo offre un numero di vantaggi: un sito di hosting è generalmente veloce da configurare ed è facile avviare un progetto su questo, e non sono necessari spese di mantenimento o controllo del server. Se imposti e avvi il tuo server interno, puoi comunque voler utilizzare un hosting pubblico per i progetti a codice aperto — è generalmente più facile per una comunità open source trovarti ed aiutarti. @@ -734,19 +739,19 @@ GitHub è leggermente differente nello spazio dei nomi che usa per i progetti ri GitHub è inoltre una organizzazione commerciale che addebita gli account che mantengono repository privati, ma chiunque può avere un account libero per ospitare qualsiasi progetto open source come preferisce. Vedremo velocemente come ottenere ciò. -### Configurare un Account Utente ### +### Configurare un account ### -La prima cosa di cui hai bisogno è configurare un account utente gratuito. Se visiti la pagina "Pricing and Signup" all'inidirizzo `http://github.com/plans` e fai click sul pulsante "Sign Up" per un account gratuito (vedi figura 4-2), sarai portato alla pagina di iscrizione. +La prima cosa di cui hai bisogno di un account gratuito. Vai alla pagina "Plans and pricing", che trovi all'inidirizzo `http://https://github.com/pricing`, e clicca sul pulsante "Sign Up" per creare un account gratuito (vedi figura 4-2), sarai portato alla pagina di iscrizione. Insert 18333fig0402.png Figura 4-2. La pagina dei piani di GitHub. -Qui devi scegliere un nome utente che non è già stato scelto nel sistema ed inserire un indirizzo e-mail che verrà associato all'account e una password (vedi Figura 4-3). +Qui devi scegliere un nome utente che non sia già stato scelto da qualcun altro, indicare un indirizzo e-mail che verrà associato all'account e una password (vedi Figura 4-3). Insert 18333fig0403.png Figura 4-3. Il form di iscrizione di GitHub. -Se ne hai una, è buona cosa aggiungere la propria chiave pubblica SSH. Abbiamo già visto come generare una nuova chiave, nella sezione "Piccole Configurazioni". Prendi il contenuto della chiave pubblica della tua coppia di chiavi, ed incollala nel box SSH Public Key. Facendo click sul link "explain ssh keys" otterrai le istruzioni dettagliate su come fare questa cosa sui maggiori sistemi operativi. +Se già ne hai una, è buona cosa aggiungere la propria chiave pubblica SSH. Abbiamo già visto come generare una nuova chiave, nella sezione "Piccole Configurazioni". Prendi il contenuto della chiave pubblica della tua coppia di chiavi, ed incollala nel box SSH Public Key. Facendo click sul link "explain ssh keys" otterrai le istruzioni dettagliate su come fare questa cosa sui maggiori sistemi operativi. Cliccare il pulsante "I agree, sign me up" ti porta al tuo nuovo pannello utente (vedi Figura 4-4). Insert 18333fig0404.png diff --git a/it/05-distributed-git/01-chapter5.markdown b/it/05-distributed-git/01-chapter5.markdown index 7e2b6a983..6d453984b 100755 --- a/it/05-distributed-git/01-chapter5.markdown +++ b/it/05-distributed-git/01-chapter5.markdown @@ -1,76 +1,76 @@ # Git distribuito # -Ora che avete un repository Git remoto messo a punto per tutti gli sviluppatore per condividere il proprio codice, e siete familiari con i comandi di base di Git nel lavoro in locale, andremo a vedere come utilizzare alcuni dei workflows distribuiti che Git offre. +Ora che avete un repository Git remoto configurato per tutti gli sviluppatore per condividere il proprio codice, e usate comunemente i comandi di base di Git per il tuo lavoro in locale, vedremo come utilizzare alcuni dei flussi di lavoro offerti da Git. -In questo capitolo, vedrete come lavorare con Git in un ambiente distribuito come contributore ed integratore. Imparerai come contribuire in maniera efficiente ad un progetto e rendere semplice la vita al gestore del progetto, oltre a come mantenere un progetto in maniera corretta con un certo numero di sviluppatori che contribuiscono ad esso. +In questo capitolo, vedremo come lavorare con Git in un ambiente distribuito come contributore e integratore. Imparerai come contribuire in maniera efficiente ad un progetto e rendere la vita al gestore del progetto il più semplice possibile, ma anche come mantenere correttamente un progetto con un certo numero di sviluppatori che vi contribuiscono. ## Workflows distribuiti ## -A differenza dei gestori di versione centralizzati (CVCSs), la natura distribuita di Git renderà possibile una maggiore flessibilità nel modo in cui gli sviluppatori collaborano nei progetti. Nel sistemi centralizzati, ogni sviluppatore è un nodo che lavora appoggiandosi più o meno ad un fulcro centrale. Con Git invece, ogni sviluppatore è potenzialmente sia un nodo che il fulcro stesso - infatti ogni sviluppatore può fornire del codice agli altri repository e mantenere un pubblico repository sul quale gli altri basano il proprio lavoro e verso il quale contribuiscono. Questo apre ad una vasta gamma di possibilità di workflow per il vostro progetto e/o il vostro team, quindi coprirò alcuni paradigmi che si avvantaggiano di questa flessibilità. Discuterò dei punti di forza e quelli deboli di ogni possibilità; potete usarne una sola, oppure prendere pezzi da diverse ed adattarle alle vostre necessità. +A differenza dei gestori di versione centralizzati (CVCS), la natura distribuita di Git ti permette di essere più flessibile nel gestire il modo in cui gli sviluppatori collaborano ai progetti. Nel sistemi centralizzati ogni sviluppatore è un nodo che lavora appoggiandosi ad un nucleo centrale più o meno ugualmente agli altri. Con Git, invece, ogni sviluppatore è potenzialmente sia un nodo che un nucleo: infatti ogni sviluppatore può contemporaneamente contribuire al codice di altri repository e mantenere un repository pubblico sul quale gli altri basino il proprio lavoro e verso il quale possano contribuire. Questo apre ad una vasta gamma di possibilità di workflow per il tuo progetto e/o il tuo gruppo. Tratterò quindi alcuni paradigmi che sfruttano questa flessibilità. Discuterò i punti di forza e le possibili debolezze di ogni design: potrai usarne uno o combinarli per adattarli alle tue necessità. ### Workflow centralizzato ### -Nei sistemi centralizzati, generalmente c'è un modo solo di collaborare. Un fulcro centrale, o repository, può accettare il codice e tutti sincronizzano il lavoro con questo. Un numero di sviluppatori sono nodi - rispetto al fulcro - e restano sincronizzati rispetto ad un luogo centrale (vedi Figura 5-1). +Nei sistemi centralizzati, generalmente c'è un solo modo per collaborare: il flusso centralizzato. Un nucleo centrale, c.d. repository, può accettare il codice e tutti sincronizzano il proprio lavoro con questo nucleo. Un numero di sviluppatori sono nodi - utenti del nucleo - e restano sincronizzati con questo nucleo centrale (vedi Figura 5-1). Insert 18333fig0501.png Figura 5-1. Worlflow centralizzato -Questo significa che se due sviluppatori clonano dal fulcro ed entrambi fanno dei cambiamenti, il primo sviluppatore che eseguirà un push verso il fulcro non avrà problemi. Il secondo invece, dovrà unire al proprio il lavoro effettuato dal primo, prima di fare un push dei cambiamenti, per non sovrascrivere il lavoro del primo. Questo accade in Git come in Subversion (o un altro CVCS), e funziona tranquillamente in Git. +Questo significa che se due sviluppatori clonano dal nucleo ed entrambi fanno dei cambiamenti, il primo sviluppatore che trasmetterà le proprie modifiche al nucleo non avrà problemi. Il secondo, invece, dovrà prima unire al proprio lavoro quello del primo e quindi potrà inviare i suoi cambiamenti, per non sovrascrivere il lavoro del primo. Questo accade in Git come in Subversion (o un altro CVCS), e questo modello funziona tranquillamente in Git. -Se hai un piccolo team, o nella tua azienda sono già abituati ad un workflow centralizzato, puoi facilmente continuare ad utilizzare questo metodo con Git. Semplicemente crea un singolo repository, e dai ad ognuno la possibilità di effettuare un push; Git non lascerà agli utenti la possibilità di sovrascriversi l'un l'altro. Se uno sviluppatore clona, esegue dei cambiamenti, e poi prova a fare un push delle proprie modifiche dopo che un altro utente ha cambiato qualcosa, il server si rifiuterà di consentire l'operazione. L'utente sarà avvisato che sta cercando di fare un push di una copia non aggiornata, e non sarà capace di caricare le proprie modifiche finché non le unirà con quelle effettuate dagli altri. -Questo metodo è utilizzato da tanti dato che è il paradigma che molti conoscono e a cui sono abituati. +Se hai un piccolo gruppo, o nella tua azienda siete già abituati ad un workflow centralizzato, puoi facilmente continuare ad utilizzare questo metodo con Git. Crea un singolo repository e dai a ognuno del tuo gruppo la possibilità di effettuare una push; Git non lascerà agli utenti la possibilità di sovrascrivere il lavoro di un l'altro. Se uno sviluppatore clona, fa dei cambiamenti, e poi prova a fare una push delle proprie modifiche dopo che un altro utente abbia già inviato le proprie modifiche, il server rifiuterà le modifiche dell'ultimo. Questi sarà avvisato che sta cercando di fare la push di una copia non aggiornata e non potrà caricare le proprie modifiche finché non le unirà con quelle effettuate dagli altri. +Molti usano questo metodo perché sono abituati a lavorare con questo paradigma. ### Workflow con manager d'integrazione ### -Dato che Git ti consente di avere multipli repositories, è possibile avere un workflow dove ogni sviluppatore ha accesso in scrittura al proprio pubblico respository, e accesso in lettura a quello degli altri. In questo scenario spesso esiste un repository che rappresenta il progetto "ufficiale". Per contribuire an progetto di questo tipo, devi creare il tuo clone pubblico del progetto e fare un push delle tue modifiche verso il progetto e successivamente chiedere al mantenitore del progetto di fare un pull delle tue modifiche. Questi può aggiungere il tuo repository come remoto, testarlo localmente, unirlo al proprio ramo e fare un push verso il proprio repository. Il processo funziona così (vedi Figura 5-2): +Poiché Git permette di avere repository multipli, è possibile avere un workflow dove ogni sviluppatore ha accesso in scrittura al proprio repository pubblico e accesso in lettura a quello degli altri. Questo scenario spesso prevede anche un repository classico che rappresenta il progetto "ufficiale". Per contribuire a progetti di questo tipo, devi creare il tuo clone pubblico del progetto e inviarvi (con una push) le tue modifiche e successivamente chiedere al mantenitore del progetto di fare una pull delle stesse. Questi può aggiungere il tuo repository come remoto, testarlo localmente, unirlo al proprio branch e fare una push verso il proprio repository. Il processo funziona così (vedi Figura 5-2): -1. Il mantenitore del progetto fa un push del proprio repository pubblico. -2. Un contributore clona il reposiory ed esegue dei cambiamenti. -3. Il contributore fa un push dei propri cambiamenti. -4. Il contributore invia al mantenitore una e-mail chiedendo di fare un pull dei cambiamenti. +1. Il mantenitore del progetto fa le push sul proprio repository pubblico. +2. Un contributore clona il reposiory ed fa delle cambiamenti. +3. Il contributore invia le modifiche al suo repository pubblico. +4. Il contributore invia al mantenitore una e-mail chiedendo di fare una pull dei cambiamenti. 5. Il mantenitore aggiunge il repository del contributore come remoto e fa un merge in locale dei cambiamenti. -6. Il mantenitore fa un push dei cambiamenti (compresi quelli aggiunti dal contributore) verso il repository principale. +6. Il mantenitore fa una push dei cambiamenti (compresi quelli aggiunti dal contributore) verso il repository principale. Insert 18333fig0502.png Figura 5-2. Workflow con manager d'integrazione -Questo è un workflow comune con siti come GitHub, dove è facile eseguire un fork di un progetto e fare un push dei propri cambiamenti nel proprio fork, in modo che tutti possano accedervi. Uno dei maggiori vantaggi di questo approccio è che puoi continuare il tuo lavoro, ed il mantenitore del repository principale può eseguire un pull dei tuoi cambiamenti in qualsiasi momento. I contributori non devono aspettare che il progetto incorpori i propri camiamenti, ed ognuno può lavorare per conto suo. +Questo è un workflow comune con siti come GitHub, dove è facile eseguire un fork di un progetto e inviare le tue modifiche al tuo fork, in modo che tutti possano accedervi. Uno dei vantaggi principali di questo approccio è che puoi continuare il tuo lavoro mentre il mantenitore del repository principale può eseguire una pull dei tuoi cambiamenti in qualsiasi momento. I contributori non devono aspettare che il progetto incorpori le modifiche: ognuno può lavorare per conto suo. -### Workflow con Dittatori e Tenenti ### +### Workflow con Dittatore e Tenenti ### -Questa è una variante del workflow con multipli repository. E' generalmente usata da grandi progetti con centinaia di collaboratori; un esempio famoso è il Kernel Linux. Molti manager d'integrazione sono in carica di certe parti del repository; sono chiamati tenenti. Tutti i tenenti hanno un manager d'integrazione conosciuto come "dittatore benevolo". Il repository del dittatore benevolo funziona come repository di riferimento dal quale tutti i collaboratori eseguono un pull. Il flusso di lavoro è il seguente (vedi Figura 5-3): +Questa è una variante del workflow con repository multipli. Viene generalmente usata da grandi progetti con centinaia di collaboratori: un esempio famoso è il Kernel Linux. Molti manager d'integrazione sono responsabili di certe parti del repository e vengono chiamati tenenti. Tutti i tenenti hanno un manager d'integrazione conosciuto come "dittatore benevolo". Il repository del dittatore benevolo è il repository di riferimento dal quale tutti i collaboratori prendono il codice. Il flusso di lavoro è il seguente (vedi Figura 5-3): -1. Normali sviluppatori lavorano nel loro ramo ed eseguono un rebase del proprio lavoro sul master. Il ramo master è quello del dittatore. -2. I tenenti eseguono l'unione del lavoro degli sviluppatori nel ramo master. -3. Il dittatore esegue l'unione dei rami master dei tenenti nel proprio ramo master. -4. Il dittatore esegue un push del proprio ramo master nel repository di riferimento, cosicché gli sviluppatori possano accedervi. +1. Sviluppatori normali lavorano sul loro branch ed eseguono un _rebase_ del proprio lavoro sul master. Il branch master è quello del dittatore. +2. I tenenti uniscono il lavoro degli sviluppatori nel proprio branch master. +3. Il dittatore esegue l'unione dei branch master dei tenenti nel proprio branch master. +4. Il dittatore esegue una push del proprio ramo master nel repository di riferimento, cosicché gli sviluppatori possano accedervi. Insert 18333fig0503.png Figura 5.3. Workflow con dittatore benevolo. -Questo tipo di workflow non è comune ma può essere utile in progetti davvero grandi, o in ambienti con una stretta gerarchia, perché consente al leader del progetto (il dittatore) di delegare molto del lavoro e raccogliere vasti sottoinsiemi di codice in momenti diversi prima di integrarli. +Questo tipo di workflow non è comune ma può essere utile in progetti molto grandi o in ambienti con una gerarchia forte, perché consente al leader del progetto (il dittatore) di delegare molto del lavoro e raccogliere vasti sottoinsiemi di codice in punti diversi prima di integrarli. -Ci sono alcuni workflow comunemente utilizzati che sono possibili con un sistema distribuito come Git, ma puoi vedere che esistono molte variazioni attuabili per farlo adattare al tuo caso specifico. Ora che hai (spero) determinato quale workflow può funzionare per te, coprirò alcuni specifici esempi su come determinare i ruoli principali per realizzare differenti workflows. +Ci sono alcuni workflow utilizzati comunemente che sono possibili con un sistema distribuito come Git, ma esistono molte possibili varianti per adattarli al tuo caso specifico. Ora che hai (spero) determinato quale combinazione di workflow possa funzionare per te, illustrerò alcuni esempi sui ruoli principali dei diversi workflow. -## Contribuire ad un Progetto ## +## Contribuire a un Progetto ## -Sai quali sono i diversi worlflows, e dovresti avere chiari i fondamentali utilizzi di Git. In questa sezione, parleremo di alcuni metodi comuni per contribuire ad un progetto. +Conosci i diversi workflow e dovresti aver chiaro i fondamentali di Git. In questa sezione imparerai alcuni metodi comuni per contribuire a un progetto. -La difficoltà maggiore nel descrivere questo processo, è che ci sono molte variazioni su come può venir fatto. Data la natura flessibile di Git, la gente può lavorare insieme in molti modi, ed è difficile descrivere come dovresti contribuire ad un progetto - ogni progetto è diverso. Alcune delle variabili coinvolte sono la quantità di contributori attivi, il workflow deciso, il tuo tipo di accesso per commit, ed eventualmente il metodo di contribuzione esterno. +La difficoltà maggiore nel descrivere questo processo è che ci sono molte variazioni su come può venir fatto. Poiché Git è molto flessibile la gente può lavorare insieme in molti modi (ed effettivamente lo fa), ed è difficile descrivere come dovresti contribuire ad un progetto: ogni progetto è diverso. Alcune delle variabili coinvolte sono la quantità di contributori attivi, il workflow adottato, il tuo tipo di accesso, ed eventualmente il metodo di contribuzione esterno. -La prima variabile è il numero di contributori attivi. Quando utenti attivamente contribuiscono con del codice a questo progetto, e quanto spesso? In molte situazioni avrai una manciata di sviluppatori con alcuni commits al giorno, o forse meno per dei progetti meno attivi. Per azienda o progetti davvero grandi, il numero di sviluppatori potrebbe essere nell'ordine delle migliaia, con dozzine o addirittura di centinaia di patches in arrivo ogni giorno. Questo è importante perché con più sviluppatori vai incontro a più problemi nell'applicare le modifiche in maniera pulita. I cambiamenti che fai potrebbero essere stati resi obsoleti o corrotti da altri che sono stati uniti mentre aspettavi che il tuo lavoro venisse approvato a applicato. Come si può tenere il proprio codice aggiornato e le proprie modifiche valide? +La prima variabile è il numero di contributori attivi. Quando utenti contribuiscono attivamente al progetto con del codice e quanto spesso? In molte casi avrai due o tre sviluppatori con poche commit quotidiane, o anche meno per dei progetti semi dormienti. Per azienda o progetti molto grandi, il numero di sviluppatori potrebbe essere nell'ordine delle migliaia, con dozzine o addirittura di centinaia di patches rilasciate ogni giorno. Questa è importante perché con più sviluppatori vai incontro a molti problemi nell'applicare le modifiche in maniera pulita o che queste possano essere facilmente integrate. I cambiamenti che fai potrebbero essere stati resi obsoleti o corrotti da altri che sono stati integrati mentre lavoravi o mentre aspettavi che il tuo lavoro venisse approvato o applicato. Come puoi mantenere il tuo codice aggiornato e le tue modifiche valide? -La prossima variabile è il workflow in uso nel progetto. E' centralizzato, con ogni sviluppatore avente lo stesso tipo di accesso in scrittura nel repository principale? Il progetto ha un manager d'integrazione che controlla tutte le modifiche? Tutte le modifiche sono riviste da più persone ed approvate? Sei coinvolto in questo processo? E' un sistema con dei tenenti, e devi fornire a loro il tuo lavoro innanzitutto? +La variabile successiva è il workflow usato nel progetto. È centralizzato, con ogni sviluppatore con lo stesso tipo di accesso in scrittura sul repository principale? Il progetto ha un manager d'integrazione che controlla tutte le modifiche? Tutte le modifiche sono riviste da più persone ed approvate? Sei coinvolto in questo processo? È un sistema con dei tenenti, e devi inviare a loro il tuo lavoro? -Il problema successivo è il tuo accesso per il commit. Il workflow richiesto per poter contribuire al progetto è molto diverso a seconda del fatto che tua abbia accesso in scrittura o no. Se non hai accesso in scrittura, come viene preferito il lavoro dei contributori? Esiste qualche regola a riguardo? Quando contribuisci per volta? Quanto spesso? +Il problema successivo riguarda i tuoi permessi per effettuare commit. Il workflow richiesto per poter contribuire al progetto è molto diverso a seconda del fatto che tua abbia accesso in scrittura o solo lettura. Se non hai accesso in scrittura, qual'è il modo preferito dal progetto per accettare il lavoro dei contributori? Esistono regole a riguardo? Quanto contribuisci? Quanto spesso? -Tutte queste domande possono influire effettivamente sul progetto e sul tipo di workflow preferibile per la tua situazione. Coprirò aspetti di ognuno di questi in una serie di casi d'uso, spaziando dal semplice al complesso; dovresti essere capace di ricostruire il workflow specifico per il tuo caso basandoti sugli esempi. +Tutte queste domande possono influire sul modo in cui contribuisci al progetto e quale tipo di workflow sia quello preferito o disponibile. Illustrerò gli aspetti di ciascuno di questi in una serie di casi d'uso, dal più semplice al più complesso: dovresti essere capace di definire il workflow specifico per il tuo caso basandoti su questi esempi. -### Linee guida per il commit ### +### Linee guida per le commit ### -Prima di guardare ai casi specifici, una breve nota riguardo ai messaggi di commit. Avere una linea guida per creare commit e aderirvi rende il lavoro con Git e la collaborazione con altri molto più semplice. Il progetto Git fornisce un documento che da alcuni suggerimenti per la creazione di messaggi di commit - puoi leggerlo nel codice sorgente di Git nel file `Documentation/SubmittingPatches`. +Prima di vedere i casi specifici faccio una breve nota riguardo i messaggi delle commit. Avere una linea guida per le commit e aderirvi rende il lavoro con Git e la collaborazione con altri molto più semplice. Il progetto di Git fornisce un documento che da molti suggerimenti circa le commit per da cui creare patch: puoi trovarlo nel codice sorgente di Git nel file `Documentation/SubmittingPatches`. -Innanzitutto, non è il caso di inserire spazi bianchi. Git fornisce un modo semplice per cercarli - prima di un commit, esegui `git diff --check`, che identifica possibili errori riguardanti spazi bianchi e li lista per te. Qui c'è un esempio, dove ho sistituiro il colore rosso del terminale con delle lettere `X`: +Innanzitutto non è il caso di inviare errori con degli spazi. Git fornisce un modo semplice per verificarli: esegui, prima di un commit, `git diff --check`, che identifica possibili errori riguardanti gli spazi e li elenca per te. Qui c'è un esempio in cui ho sostituiro il colore rosso del terminale con delle `X`: $ git diff --check lib/simplegit.rb:5: trailing whitespace. @@ -80,41 +80,39 @@ Innanzitutto, non è il caso di inserire spazi bianchi. Git fornisce un modo sem lib/simplegit.rb:26: trailing whitespace. + def command(git_cmd)XXXX -Se esegui quel commando prima del commit, puoi vedere se stai per inserire degli spazi bianchi che potrebbero infastidire altri sviluppatori. +Se esegui il commando prima della commit, puoi vedere se stai per committare degli spazi bianchi che potrebbero infastidire altri sviluppatori. -In seguito, prova a rendere ogni commit un insieme logico di cambiamenti. Se puoi, cerca di rendere i cambiamenti "digeribili" - non scrivere codice per un intero weekend su cinque diversi problemi e poi fare un commit massivo il Lunedì. Anche se non esegui commit nel weekend, usa l'area di staging il Lunedì per suddividere il tuo lavoro in almeno un commit per problema, con un utile messaggio. Se diverse modifiche coinvolgono lo stesso file, usa `git add --patch` per aggiungere file in maniera parziale all'area di staging (spiegato nel dettaglio nel capitolo 6). Il risultato finale sarà lo stesso sia che tu faccia un commit sia che tu ne faccia cinque, finché tutti i cambiamenti sono aggiunti ad un certo punto, per cui cerca di rendere le cose più semplici ai tuoi colleghi sviluppatori quando devono controllare i tuoi cambiamenti. Questo approccio inoltre rende più semplice includere o escludere uno dei cambiamenti nel caso ti serva in seguito. Il capitolo 6 descrive una manciata di utili trucchetti di Git per riscrivere la storia ed aggiungere files all'area di staging in maniera interattiva - usa questi strumenti per mantenere una comprensibile cronologia. +Cerca quindi di aver per ciascuna commit un insieme logico di modifiche. Se puoi, cerca di rendere i cambiamenti "digeribili": non lavorare per un intero fine settimana su cinque diversi problemi per fare poi una commit massiva il lunedì. Anche se non fai commit nel weekend, il lunedì usa l'area di staging per suddividere il tuo lavoro in almeno un commit per problema con un messaggio utile per ciascuna. Se modifiche diverse coinvolgono lo stesso file, usa `git add --patch` per aggiungere parti del file all'area di staging (trattato in dettaglio nel capitolo 6). Il risultato finale sarà lo stesso che tu faccia una o cinque commit quando queste vengano integrate in un punto, per cui cerca di rendere le cose più semplici ai tuoi colleghi sviluppatori quando devono controllare le tue modifiche. Questo approccio inoltre rende più semplice includere o escludere alcuni dei cambiamenti, nel caso ti serva successivamente. Il capitolo 6 descrive una serie di trucchi di Git utili per riscrivere la storia e aggiungere interattivamente file all'area di staging: usa questi strumenti per mantenere la cronologia pulita e comprensibile. -L'ultima cosa da tenere in mente è il messaggio di commit. Prendere l'abitudine di creare messaggi di commit di qualità rende usare e collaborare tramite Git molto più semplice. Come regola generale, i tuoi messaggi dovrebbero iniziare con una singola linea di al massimo 50 caratteri che descrive il set di cambiamenti in maniera concisa, seguito da una linea bianca, ed in seguito una spiegazione dettagliata. Il progetto Git richiede che la spiegazione dettagliata includa il motivo del cambiamento ed il confronto con il comportamento precedente - questa è una buona linea guida da seguire. E' anche una buona idea usare la forma imperativa nel messaggio. In altre parole, usa dei comandi. Al posto di "Ho aggiunto dei test per" oppure "Aggiungere dei test per", usa "Aggiunti dei test per". -Questo è un modello scritto originariamente da Tim Pope su tpope.net: +L'ultima cosa da tenere a mente è il messaggio di commit. Prendere l'abitudine di creare messaggi di commit di qualità rende l'uso e la collaborazione tramite Git molto più semplice. Come regola generale, i tuoi messaggi dovrebbero iniziare con una sola linea di massimo 50 caratteri che descriva sinteticamente l'insieme delle modifiche seguito da una linea bianca e quindi una spiegazione dettagliata. Il progetto di Git prevede che una spiegazione molto dettagliata includa il motivo della modifica e confrontare l'implementazione committata con la precedente: questa è una buona linea guida da seguire. È una buona idea anche usare l'imperativo presente in questi messaggi. In altre parole, usa dei comandi. Al posto di "Ho aggiunto dei test per" o "Aggiungendo test per", usa "Aggiungi dei test per". +Questo modello è stato originariamente scritto da Tim Pope su tpope.net: Breve (50 caratteri o meno) riassunto delle modifiche - Testo di spiegazione più dettagliato, se necessario. Suddividilo ogni - circa 72 caratteri. In alcuni contesti, la prima linea è trattata - come l'oggetto di un'email, ed il resto come il contenuto. La linea - vuota che separa il riassunto dal testo è importante (a meno che tu - non ometta il testo del tutto); strumenti come rebase possono andare - in confusione senza di essa. + Spiegazione più dettagliata, se necessario. Manda a capo ogni 72 caratteri + circa. In alcuni contesti, la prima linea è trattata come l'oggetto di + un'email, ed il resto come il contenuto. La linea vuota che separa l'oggetto + dal testo è importante (a meno che tu non ometta il testo del tutto): + strumenti come rebase possono confondersi se non dovesse esserci. - Ulteriore paragrafo dopo alcune linee vuote. + Ulteriori paragrafi vanno dopo altre linee vuote. - Le liste puntate sono concesse - - Di solito un trattino od un asterisco viene usato come separatore, - preceduto da uno spazio singolo, con linee vuote tra i punti, - ma le convenzioni potrebbero variare in questo caso + - Di solito viene usato un trattino o un asterisco come separatore, + preceduto da uno spazio singolo, con delle linee vuote tra i punti, + ma le convenzioni possono essere diverse -Se tutti i tuoi messaggi di commit hanno questo aspetto, le cose saranno molto più semplici per per te e gli sviluppatore con cui lavori. Il progetto Git ha dei messaggi di commit ben formattati - ti incoraggio ad eseguire `git log --no-merges` per vedere qual'è l'aspetto di una cronologia ben leggibile. +Se tutti i tuoi messaggi di commit fossero così, per te e gli altri sviluppatori con cui lavori le cose saranno molto più semplici per te e per gli sviluppatore con cui lavori. Il progetto di Git ha dei messaggi di commit ben formattati: ti incoraggio a eseguire `git log --no-merges` per vedere qual è l'aspetto di una cronologia ben leggibile. -Nei seguenti esempi, ed attraverso la maggior parte di questo libro, per brevità non formatterò i messaggi così accuratamente; invece userò l'opzione `-m` di `git commit`. -Fa come dico, non come faccio. +Negli esempi che seguono e nella maggior parte di questo libro, per brevità, non formatterò i messaggi accuratamente come descritto: userò invece l'opzione `-m` di `git commit`. Fa' come dico, non come faccio. -### Piccoli team privati ### +### Piccoli gruppi privati ### -La configurazione più semplice e facile da incontrare è il progetto privato con uno o due sviluppatori. Con privato, intendo codice a sorgente chiuso - non accessibile dal resto del mondo. Tu e gli altri sviluppatori avete tutti accesso per il push verso il repository. +La configurazione più semplice che probabilmente incontrerai sarà di un progetto privato con uno o due sviluppatori. Con privato intendo codice a sorgente chiuso: non accessibile al resto del mondo. Tu e gli altri sviluppatori avete accesso in scrittura al repository. -In questo ambiente, puoi utilizzare un workflow simile a quello che magari stai già usando con Subversion od un altro sistema centralizzato. Hai ancora i vantaggi (ad esempio) di poter eseguire commit da offline e la creazione di rami (ed unione degli stessi) molto più semplici, ma il workflow può restare simile; la differenza principale è che, nel momento del commit, l'unione avviene nel tuo repository piuttosto che in quello sul server. -Vediamo come potrebbe essere la situazione quando due sviluppatori iniziano a lavorare insieme con un repository condiviso. Il primo sviluppatore, John, clona in repository, fa dei cambiamenti ed esegue il commit localmente. (Sostituisco il messaggio di protocollo con `...` in questi esempi per brevità.) +Con questa configurazione, puoi utilizzare un workflow simile a quello che magari stai già usando con Subversion o un altro sistema centralizzato. Hai comunque i vantaggi (ad esempio) di poter eseguire commit da offline e la creazione di rami (ed unione degli stessi) molto più semplici, ma il workflow può restare simile; la differenza principale è che, nel momento del commit, l'unione avviene nel tuo repository piuttosto che in quello sul server. +Vediamo come potrebbe essere la situazione quando due sviluppatori iniziano a lavorare insieme con un repository condiviso. Il primo sviluppatore, John, clona in repository, fa dei cambiamenti ed esegue il commit localmente. (In questi esempi sostituirò, per brevità, il messaggio del protocollo con `...`) # Computer di John $ git clone john@githost:simplegit.git @@ -126,7 +124,7 @@ Vediamo come potrebbe essere la situazione quando due sviluppatori iniziano a la [master 738ee87] rimosso valore di default non valido 1 files changed, 1 insertions(+), 1 deletions(-) -Il secondo sviluppatore, Jessica, fa la stessa cosa - clona il repository ed esegue dei cambiamenti: +Il secondo sviluppatore, Jessica, fa la stessa cosa - clona il repository e committa le modifiche: # Computer di Jessica $ git clone jessica@githost:simplegit.git @@ -138,7 +136,7 @@ Il secondo sviluppatore, Jessica, fa la stessa cosa - clona il repository ed ese [master fbff5bc] aggiunto il processo di reset 1 files changed, 1 insertions(+), 0 deletions(-) -Ora, Jessica esegue un push del suo lavoro nel server: +Ora, Jessica invia il suo lavoro al server con una push: # Computer di Jessica $ git push origin master @@ -146,7 +144,7 @@ Ora, Jessica esegue un push del suo lavoro nel server: To jessica@githost:simplegit.git 1edee6b..fbff5bc master -> master -Anche John cerca di eseguire un push: +Anche John cerca di eseguire una push: # Computer di John $ git push origin master @@ -154,7 +152,7 @@ Anche John cerca di eseguire un push: ! [rejected] master -> master (non-fast forward) error: failed to push some refs to 'john@githost:simplegit.git' -A John non è consentito eseguire un push perché Jessica ha fatto lo stesso nel frattempo. Questo è particolarmente importante se sei abituato a Subversion, perché avrai notato che i due sviluppatori non hanno modificato lo stesso file. Anche se Subversion automaticamente esegue questa unione nel server se differenti file sono stati modificati, in Git devi unire i cambiamenti localmente. John deve recuperare i cambiamenti di Jessica ed unirli ai suoi prima di poter eseguire il push: +A John non è permesso fare un push perché nel frattempo lo ha già fatto Jessica. Questo è particolarmente importante se sei abituato a Subversion, perché vedrai che i due sviluppatori non hanno modificato lo stesso file. Sebbene Subversion unisca automaticamente sul server queste commit se i file modificati sono diversi, in Git sei tu che devi farlo localmente. John deve quindi scaricare le modifiche di Jessica e unirle alle sue prima di poter fare una push: $ git fetch origin ... @@ -166,36 +164,36 @@ A questo punto, il repository locale di John somiglia a quello di figura 5-4. Insert 18333fig0504.png Figura 5-4. Il repository iniziale di John. -John ha a disposizione i cambiamenti che Jessica ha eseguito, ma deve unirli ai suoi prima di avere la possibilità di eseguire un push: +John sa quali sono le modifiche di Jessica, ma deve unirle alle sue prima poter fare una push: $ git merge origin/master Merge made by recursive. TODO | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) -L'unione fila liscia - ora la cronologia dei commit di John sarà come quella di Figura 5-5. +L'unione fila liscia e ora la cronologia delle commit di John sarà come quella di Figura 5-5. Insert 18333fig0505.png Figura 5-5. Il repository di John dopo aver unito origin/master. -Ora, John può testare il suo codice per essere sicuro che funzioni anche correttamente e può eseguire il push del tutto verso il server: +John ora può testare il suo codice per essere sicuro che continui a funzionare correttamente e può quindi eseguire la push del tutto sul server: $ git push origin master ... To john@githost:simplegit.git fbff5bc..72bbc59 master -> master -Infine, la cronologia dei commit di John somiglierà a quella di figura 5-6. +La cronologia dei commit di John somiglierà quindi a quella di figura 5-6. Insert 18333fig0506.png -Figura 5-6. La cronologia di John dopo avere eseguito il push verso il server. +Figura 5-6. La cronologia di John dopo avere eseguito la push verso il server. -Nel frattempo, Jessica sta lavorando su un altro ramo. Ha creato un ramo chiamato `problema54` ed ha eseguito tre commit su quel ramo. Non ha ancora recuperato i cambiamenti di John, per cui la sua cronologia di commit è quella di Figura 5-7. +Jessica nel frattempo sta lavorando a un altro ramo. Ha creato un branch chiamato `problema54` e ha eseguito tre commit su quel branch. Poiché non ha ancora recuperato le modifiche di John la sua cronologia è quella della Figura 5-7. Insert 18333fig0507.png Figura 5-7. La cronologia iniziale di Jessica. -Jessica vuole sincronizzarsi con John, così recupera: +Jessica vuole sincronizzarsi con John, quindi esegue: # Computer di Jessica $ git fetch origin @@ -203,12 +201,12 @@ Jessica vuole sincronizzarsi con John, così recupera: From jessica@githost:simplegit fbff5bc..72bbc59 master -> origin/master -Questo recupera il lavoro che John ha eseguito nel frattempo. La cronologia di Jessica ora è quella di Figura 5-8. +Con cui recupera il lavoro che nel frattempo John ha eseguito. La cronologia di Jessica ora è quella di Figura 5-8. Insert 18333fig0508.png Figura 5-8. La cronologia di Jessica dopo aver recuperato i cambiamenti di John. -Jessica pensa che il suo ramo sia pronto, però vuole sapere con cosa deve unire il suo lavoro prima di eseguire il push. Esegue `git log` per scoprirlo: +Jessica pensa che il suo ramo sia pronto, però vuole sapere con cosa deve unire il suo lavoro prima di eseguire la push. Esegue quindi `git log` per scoprirlo: $ git log --no-merges origin/master ^problema54 commit 738ee872852dfaa9d6634e0dea7a324040193016 @@ -217,13 +215,13 @@ Jessica pensa che il suo ramo sia pronto, però vuole sapere con cosa deve unire rimosso valore di default non valido -Ora, Jessica può unire il suo lavoro al ramo master, unire il lavoro di John (`origin/master`) nel suo ramo `master`, e poi eseguire il push verso il server di nuovo. Per prima cosa, torna nel suo ramo master per integrare il suo lavoro: +Ora, Jessica può unire il lavoro del suo branch nel suo master, quindi le modifiche di John (`origin/master`) nel suo branch `master`, e ritrasmettere il tutto al server con una push. Per prima cosa torna al suo branch master per integrare il lavoro svolto nell'altro branch: $ git checkout master Switched to branch "master" Your branch is behind 'origin/master' by 2 commits, and can be fast-forwarded. -Può unire sia `origin/master` che `problema54` per primo - sono entrambi a monte, per cui l'ordine non conta. Il risultato finale sarà lo stesso a prescindere dall'ordine scelto; solo la cronologia sarà leggermente differente. Lei sceglie di unire `problema54` per primo: +Può decidere di unire prima `origin/master` o `problema54`: entrambi sono flussi principali, per cui non conta l'ordine. Il risultato finale sarà lo stesso a prescindere dall'ordine scelto, ma la cronologia sarà leggermente differente. Lei sceglie di fare il merge prima di `problema54`: $ git merge problema54 Updating fbff5bc..4af4298 @@ -232,7 +230,7 @@ Può unire sia `origin/master` che `problema54` per primo - sono entrambi a mont lib/simplegit.rb | 6 +++++- 2 files changed, 6 insertions(+), 1 deletions(-) -Non ci sono problemi; come puoi vederem è stato tutto semplice. Ora Jessica unisce il lavoro di John (`origin/master`): +Non ci sono stati problemi: come puoi vedere tutto è stato molto semplice. Quindi Jessica unisce il lavoro di John (`origin/master`): $ git merge origin/master Auto-merging lib/simplegit.rb @@ -245,30 +243,30 @@ Tutto viene unito correttamente, e la cronologia di Jessica è come quella di Fi Insert 18333fig0509.png Figura 5-9. La cronologia di Jessica dopo aver unito i cambiamenti di John. -Ora `origin/master` è raggiungibile dal ramo `master` di Jessica, cosicché lei sia capace di eseguire dei push successivamente (assumento che John non abbia fatto lo stesso nel frattempo): +Ora `origin/master` è raggiungibile dal ramo `master` di Jessica, cosicché lei sia capace di eseguire delle push con successo (supponendo che John non abbia fatto altre push nel frattempo): $ git push origin master ... To jessica@githost:simplegit.git 72bbc59..8059c15 master -> master -Ogni sviluppatore ha eseguito alcuni commit ed unito il proprio lavoro con quello di altri con successo; vedi Figura 5-10. +Ogni sviluppatore ha eseguito alcune commit ed unito con successo il proprio lavoro con quello degli altri; vedi Figura 5-10. Insert 18333fig0510.png Figura 5-10. La cronologia di Jessica dopo aver eseguito il push dei cambiamenti verso il server. -Questo è uno dei workflow più semplici. Lavori per un pò, generalmente in un ramo, ed unisci il tutto al ramo master questo è pronto ad essere integrato. Quando vuoi condividere il tuo lavoro, uniscilo al tuo ramo master, poi recupera ed unisci `origin/master` se è cambiato, ed infine esegui il push verso il ramo `master` nel server. La sequenza è simile a quella di Figura 5-11. +Questo è uno dei workflow più semplici. Lavori per un po', generalmente in un branch, ed unisci il tutto al branch master quando è pronto per essere integrato. Quando vuoi condividere questo lavoro lo unisci al tuo branch master e poi scarichi ed unisci `origin/master`, se è cambiato, e infine esegui la push verso il branch `master` nel server. La sequenza è simile a quella in Figura 5-11. Insert 18333fig0511.png -Figura 5-11. La sequenza generale di eventi per un semplice workflow con Git a più sviluppatori. +Figura 5-11. La sequenza generale di eventi per un workflow semplice con Git a più sviluppatori. ### Team privato con manager ### -In questo prossimo scenario, scoprirai ai ruoli di un contributore in un gruppo privato più grande. Imparerai come lavorare in un ambiente dove piccoli gruppi collaborano a delle funzionalità e poi queste contribuzioni sono integrate da un altro componente. +In questo scenario, scoprirai i ruoli di contributore in un gruppo privato più grande. Imparerai come lavorare in un ambiente dove gruppi piccoli collaborano a delle funzionalità e poi queste contribuzioni sono integrate da un altra persona. -Supponiamo che John e Jessica stiano lavorando insieme su una funzionalità, mentre Jessica e Josie si stanno concentrando su una seconda. In questo caso, l'azienda sta usando un workflow con manager d'integrazione dove il lavoro di ogni gruppo è integrato solo da certi ingegneri, ed il ramo `master` del repository principale può essere aggiornato solo dai suddetti ingegneri. In questo scenario, tutto il lavoro è eseguito sui rami suddivisi per team, ed unito dagli integratori in seguito. +Supponiamo che John e Jessica stiano lavorando insieme a una funzionalità, mentre Jessica e Josie si stiano concentrando a una seconda. In questo caso l'azienda sta usando un workflow con manager d'integrazione dove il lavoro di ogni gruppo è integrato solo da alcuni ingegneri, ed il branch `master` del repository principale può essere aggiornato solo da questi. In questo scenario, tutto il lavoro è eseguito sui rami suddivisi per team, e unito successivamente dagli integratori. -Seguiamo il workflow di Jessica mentre lavora sulle due funzionalità, collaborando parallelamente con due diversi sviluppatori in questo ambiente. Assumendo che lei abbia già clonato il suo repository, decide di lavorare su `funzionalitaA` per prima. Crea un nuovo ramo per la funzionalità ed esegue del lavoro su di esso. +Seguiamo il workflow di Jessica mentre lavora sulle due funzionalità, collaborando parallelamente con due diversi sviluppatori in questo ambiente. Assumendo che lei abbia già clonato il suo repository, decide di lavorare prima alla `funzionalitaA`. Crea un nuovo branch per la funzionalità e ci lavora. # Computer di Jessica $ git checkout -b featureA @@ -278,21 +276,21 @@ Seguiamo il workflow di Jessica mentre lavora sulle due funzionalità, collabora [featureA 3300904] aggiunto il limite alla funzione di log 1 files changed, 1 insertions(+), 1 deletions(-) -A questo punto, lei ha bisogno di condividere il suo lavoro con John, così lei esegue il push del ramo `funzionalitaA` sul server. Jessica non ha accesso per il push al ramo `master` - solo gli integratori ce l'hanno - perciò deve eseguire il push verso un altro ramo per poter collaborare con John: +A questo punto lei deve condividere il suo lavoro con John, così fa la push sul server del branch `funzionalitaA`. Poiché Jessica non ha permessi per fare la push sul ramo `master` (solo gli integratori ce l'hanno) deve perciò eseguire la push su un altro branch per poter collaborare con John: $ git push origin funzionalitaA ... To jessica@githost:simplegit.git * [new branch] featureA -> featureA -Jessica manda una e-mail a John dicendogli che ha eseguito il push del suo lavoro in un ramo chiamato `funzioanlitaA` e lui può dargli un'occhiata. Mentre aspetta una risposta da John, Jessica decide di iniziare a lavorare su `funzionalitaB` con Josie. Per iniziare, crea un nuovo ramo basandosi sul ramo `master` del server: +Jessica manda una e-mail a John dicendogli che fatto la push del suo lavoro su un branch chiamato `funzioanlitaA` chiedendogli se lui può dargli un'occhiata. Mentre aspetta una risposta da John, Jessica decide di iniziare a lavorare su `funzionalitaB` con Josie. Per iniziare, crea un nuovo branch basandosi sul branch `master` del server: - # Computer di Jessica + # Computer di Jessica $ git fetch origin $ git checkout -b featureB origin/master Switched to a new branch "featureB" -Ora, Jessica esegue un paio di commit sul ramo `funzionalitaB`: +Quindi Jessica esegue un paio di commit sul branch `funzionalitaB`: $ vim lib/simplegit.rb $ git commit -am 'resa la funzione ls-tree ricorsiva' @@ -306,10 +304,9 @@ Ora, Jessica esegue un paio di commit sul ramo `funzionalitaB`: Il repository di Jessica è come quello di Figura 5-12. Insert 18333fig0512.png -Figura 5.12. La cronologia iniziale dei commit di Jessica -Figure 5-12. Jessica’s initial commit history. +Figura 5.12. La cronologia iniziale delle commit di Jessica -Lei è pronta ad eseguire un push del proprio lavoro, ma riceve una e-mail da Josie la quale dice che una parte del lavoro era già stato messo nel server nel ramo chiamato `funzionalitaBee`. Jessica innanzitutto deve unire questi cambiamenti ai suoi prima di poter eseguire il push verso il server. Può recuperare il lavoro di Josie usando `git fetch`: +Quando è pronta a eseguire una push del proprio lavoro riceve una e-mail da Josie che le dice che una parte del lavoro era già stato caricato sul server nel branch chiamato `funzionalitaBee`. Jessica deve unire prima le modifiche al server alle sue per poter fare la push verso il server. Può recuperare il lavoro di Josie usando `git fetch`: $ git fetch origin ... @@ -324,32 +321,32 @@ Jessica ora può unire il suo lavoro a quello di Josie con `git merge`: lib/simplegit.rb | 4 ++++ 1 files changed, 4 insertions(+), 0 deletions(-) -C'è un problema - deve eseguire il push del suo ramo `funzionalitaB` verso il ramo `funzionalitaBee` nel server. Può farlo specificando il ramo locale seguito dal simbolo dei due punti (:) seguito a sua volta dal nome del ramo remoto destinazione del comando `git push`: +C'è un piccolo problema: deve fare la push del suo branch `funzionalitaB` sul branch `funzionalitaBee` del server. Può farlo specificando il branch locale seguito da due punti (:) seguito a sua volta dal nome del branch remoto di destinazione al comando `git push`: $ git push origin funzionalitaB:funzionalitaBee ... To jessica@githost:simplegit.git fba9af8..cd685d1 featureB -> featureBee -Questo è chiamato _refSpec_. Vedi il capitolo 9 per una discussione più dettagliata sui refspec di Git ed altre cose che puoi fare con loro. +Questo è detto _refSpec_. Vedi il capitolo 9 per una discussione più dettagliata sui refspec di Git e cosa ci puoi fare. -Ora John manda una mail a Jessica dicendo che ha eseguito il push di alcuni cambiamenti sul ramo `funzionalitaA` e le chiede di controllarli. Lei esegue `git fetch` per recuperare questi cambiamenti: +John manda una mail a Jessica dicendole che ha fatto la push di alcune modifiche sul branch `funzionalitaA` e le chiede di controllarle. Lei esegue `git fetch` per scaricarle: $ git fetch origin ... From jessica@githost:simplegit 3300904..aad881d featureA -> origin/featureA -Ora, lei può vedere cos'è stato cambiato con `git log`: +E può vederle con `git log`: $ git log origin/funzionalitaA ^funzionalitaA commit aad881d154acdaeb2b6b18ea0e827ed8a6d671e6 Author: John Smith Date: Fri May 29 19:57:33 2009 -0700 - cambianto l'output del log da 30 a 25 + cambiato l'output del log da 25 a 30 -Finalmente, unisce il lavoro di John al suo sul ramo `funzionalitaA`: +Infine unisce il lavoro di John al suo nel branch `funzionalitaA`: $ git checkout funzionalitaA Switched to branch "funzionalitaA" @@ -359,7 +356,7 @@ Finalmente, unisce il lavoro di John al suo sul ramo `funzionalitaA`: lib/simplegit.rb | 10 +++++++++- 1 files changed, 9 insertions(+), 1 deletions(-) -Jessica vuole aggiustare qualcosa, così esegue un altro commit ed un push verso il server: +Jessica vuole aggiustare qualcosa e fa un'altro commit ed una push verso il server: $ git commit -am 'leggero aggiustamento' [featureA ed774b3] leggero aggiustamento @@ -369,26 +366,26 @@ Jessica vuole aggiustare qualcosa, così esegue un altro commit ed un push verso To jessica@githost:simplegit.git 3300904..ed774b3 featureA -> featureA -Ora la cronologia dei commit di Jessica sarà come quella di Figura 5-13. +La cronologia delle commit di Jessica ora sarà come quella della Figura 5-13. Insert 18333fig0513.png -Figura 5-13. La cronologia di Jessica dopo aver eseguito il commit sul ramo. +Figura 5-13. La cronologia di Jessica dopo aver eseguito la commit sul branch. -Jessica, Josie e John informano gli integratori che i rami `funzionalitaA` e `funzionalitaB` sono sul server e pronti per l'integrazione nel ramo `master`. Dopo l'integrazione di questi rami nel `master`, un recupero del ramo principale aggiungerà anche i nuovi commit, rendendo la cronologia dei commit come quella di figura 5.14. +Jessica, Josie e John informano gli integratori che i rami `funzionalitaA` e `funzionalitaB` che sono sul server sono pronti per l'integrazione nel `master`. Dopo l'integrazione di questi branch nel `master`, una fetch scaricherà tutte queste nuove commit, rendendo la cronologia delle commit come quella della Figura 5.14. Insert 18333fig0514.png Figura 5.14. La cronologia di Jessica dopo aver unito entrambi i rami. -Molti gruppi migrano verso Git per la sua capacità di avere più team a lavorarare in parallelo, unendo le differenti linee di lavoro alla fine del processo. L'abilità di piccoli sotto gruppi di una squadra di collaborare tramite rami remoti senza necessariamente dover coinvolgere o ostacolare l'intero team è un grande beneficio di Git. La sequenza per il workflow che hai appena visto è rappresentata dalla Figura 5-15. +Molti gruppi migrano a Git per la sua capacità di avere gruppi che lavorino in parallelo, unendo le differenti righe di lavoro alla fine del processo. La possibilità che piccoli sottogruppi del team possano collaborare con branch remoti senza dover necessariamente coinvolgere o ostacolare l'intero team è un grande beneficio di Git. La sequenza del workflow che hai appena visto è rappresentata nella Figura 5-15. Insert 18333fig0515.png Figura 5-15. Sequenza base di questo workflow con team separati. ### Piccolo progetto pubblico ### -Contribuire ad un progetto pubblico è leggermente differente. Dato che non hai il permesso di aggiornare direttamente i rami del progetto, devi far avere il tuo lavoro ai mantenitori in qualche altro modo. Questo esempio descrive la contribuzione via fork su host Git che lo supportano in maniera semplice. I siti repo.or.cz e GitHub lo supportano, e molti altri mantenitori di progetti si aspettano questo tipo di contribuzione. La prossima sezione si occupa di progetti che preferiscono accettare patch via e-mail +Contribuire ad un progetto pubblico è leggermente differente. Poiché non hai il permesso di aggiornare direttamente i rami del progetto, devi far avere il tuo lavoro ai mantenitori in qualche altro modo. Questo primo esempio descrive come contribuire con i fork su host Git che lo supportano in maniera semplice. I siti di repo.or.cz e GitHub lo supportano, e molti mantenitori di progetti si aspettano questo tipo di contribuzione. La sezione successiva tratta i progetti che preferiscono ricevere le patch per e-mail -Innanzitutto, probabilemnte dovrai clonare il repository principale, creare un ramo per le modifiche che hai in programma di fare, e fare li il tuo lavoro. La sequenza è grosso modo questa: +Per iniziare probabilemnte dovrai clonare il repository principale, creare un branch per le modifiche che programmi di fare, quindi lavorarci. La sequenza è grosso modo questa: $ git clone (url) $ cd project @@ -398,19 +395,19 @@ Innanzitutto, probabilemnte dovrai clonare il repository principale, creare un r $ (lavoro) $ git commit -Potresti voler usare `rebase -i` per ridurre il tuo lavoro ad un singolo commit, o riorganizzare il lavoro nei commit per rendere le modifiche semplice da controllare per il mantenitore - vedi il Capitolo 6 per altre informazioni sul rebasing interattivo. +Potresti voler usare `rebase -i` per ridurre il tuo lavoro a una singola commit, o riorganizzare il lavoro delle commit per facilitare il lavoro di revisione dei mantenitori - vedi il Capitolo 6 per altre informazioni sul rebase interattivo. -Quando il tuo lavoro sul ramo è completato e sei pronto per farlo avere ai mantenitori, vai alla pagina principale del progetto e clicca sul link "Fork", creando una tua copia scrivibile del progetto. Dovrai poi aggiungere questo nuovo URL di repository come secondo URL remoto, in questo caso chiamato `miofork`: +Quando il lavoro sul tuo branch è completato e sei pronto per condividerlo con i mantenitori, vai alla pagina principale del progetto e clicca sul pulsante "Fork", creando la tua copia modificabile del progetto. Dovrai quindi aggiungere l'URL di questo nuovo repository come un secondo remoto, chiamato in questo caso `miofork`: $ git remote add miofork (url) -Dovrai eseguire un push del tuo lavoro verso esso. E' più semplice eseguire il push del ramo su cui stai lavorando piuttosto che unirlo al ramo master ed eseguire il push di quest'ultimo. La ragione è che se il tuo lavoro non è accettato, oppure lo è solo in parte, non dovrai tornare indietro nei commit sul tuo ramo master. Se i mantenitori uniscono, eseguono un rebase, o prendono pezzi dal tuo lavoro, riuscirai in ogni caso a recuperarlo eseguendo un pull dal loro repository: +E dovrai eseguire una push del tuo lavoro verso il nuovo repository. È più semplice fare la push del branch a cui stai lavorando piuttosto che unirlo al tuo master e fare la push di quest'ultimo. La ragione è che se il tuo lavoro non verrà accettato, oppure lo sarà solo in parte, non dovrai ripristinare il tuo master. Se i mantenitori uniscono, fanno un rebase, o prendono pezzi dal tuo lavoro col cherry-pick, otterrai il nuovo master alla prossima pull dal loro repository: $ git push myfork funzionalitaA -Quando hai eseguito il push del tuo lavoro verso il tuo fork, devi farlo sapere al mantenitore. Questo passaggio è chiamato spesso richiesta di pull (pull request), e puoi farlo sia tramite il sito - GitHub ha un pulsante "pull request" che automaticamente notifica al mantenitore - o eseguire il comando `git request-pull` ed inviare l'output il mantenitore manualmente. +Quando avrai eseguito la push del tuo lavoro sul tuo fork, devi avvisare i mantenitori. Questo passaggio viene spesso definito "richiesta di pull" (pull request), e puoi farlo tramite lo stesso sito - GitHub ha un pulsante "pull request" che automaticamente notifica i mantenitori - o eseguire il comando `git request-pull` e inviare manualmente via email l'output ai mantenitori. -Il comando `request-pull` riceve come parametri il ramo base sul quale vuoi far applicare le modifiche ed l'URL del repository Git da cui vuoi estrarle, ed in output fornisce un riassunto di tutte queste modifiche. Per esempio, se Jessica volesse inviare a John una richiesta di pull, e lei ha eseguito due commit sul ramo di cui ha appena effettuato il push, può eseguire questo: +Il comando `request-pull` riceve come parametri il branch di base sul quale vuoi far applicare le modifiche e l'URL del repository Git da cui vuoi che le prendano, e produce il sommario di tutte queste modifiche in output. Se, per esempio, Jessica volesse inviare a John una richiesta di pull, e avesse eseguito due commit sul branch di cui ha appena effettuato il push, può eseguire questo: $ git request-pull origin/master miofork The following changes since commit 1edee6b1d61823a2de3b09c160d7080b8d1b3a40: @@ -428,9 +425,9 @@ Il comando `request-pull` riceve come parametri il ramo base sul quale vuoi far lib/simplegit.rb | 10 +++++++++- 1 files changed, 9 insertions(+), 1 deletions(-) -L'output può essere inviato al mantenitore. Esso riporta da dove è stato creato il nuovo ramo, un riassunto dei commit e dice da dove si può eseguire il pull. +L'output può essere inviato ai mantenitori: riporta da dove è stato creato il nuovo branch, un riassunto delle commit e da dove si possono scaricare. -Su un progetto dove non sei il mantenitore, è generalmente comune avere un ramo come `master` sempre collegato a `origin/master` ed eseguire il tuo lavoro su rami che puoi eliminare nel caso non venissero accettati. Avere il lavoro suddiviso in rami inoltre rende semplice per te eseguire il rebase del tuo lavoro se è stato modificato il repository principale ed i tuoi commit non possono venire applicati in maniera pulita. Per esempio, se vuoi aggiungere un secondo argomento di lavoro ad un progetto, non continuare a lavorare sul ramo di cui hai appena fatto il push - creane un altro partendo dal ramo `master` del repository: +In un progetto dove non sei il mantenitore normalmente è comodo avere un branch come `master` sempre collegato a `origin/master` e lavorare su altri branch che puoi eliminare nel caso non venissero accettati. Suddividere il lavoro in branch per argomento ti rende più semplice ribasare il tuo lavoro se il repository principale è stato modificato e le tue commit non possono venire applicate in maniera pulita. Se per esempio vuoi aggiungere un'altra caratteristica al progetto, invece di continuare a lavorare sul branch di cui hai appena fatto la push, creane un altro partendo dal `master` del repository: $ git checkout -b funzionalitaB origin/master $ (lavoro) @@ -439,25 +436,25 @@ Su un progetto dove non sei il mantenitore, è generalmente comune avere un ramo $ (email al mantenitore) $ git fetch origin -Ora, ognuno dei tuoi lavori è separato, simile ad una coda di modifiche. Puoi riscrivere, modificare o effettuare un rebase, senza che i rami interferiscano o dipendano l'uno dall'altro, come in Figura 5-16. +Ora ognuno dei tuoi lavori è separato come in una coda di modifiche che puoi riscrivere, ribasare e modificare senza che gli argomenti interferiscano o dipendano dagli altri, come in Figura 5-16. Insert 18333fig0516.png -Figura 5-16. Conologia iniziale dei commit con del lavoro su funzionalitaB. +Figura 5-16. Conologia iniziale col lavoro su funzionalitaB. -Diciamo che il mantenitore del progetto ha eseguito il pull, una manciata di altre modifiche e provato il tuo primo ramo ma non riesce più ad applicare tali modifiche in maniera pulita. In questo caso, puoi provare ad effettuare un rebase di quel ramo basandoti sul nuovo `origin/master`, risolvere i conflitti e poi inviare di nuovo i tuoi cambiamenti: +Supponiamo che il mantenitore del progetto ha inserito una manciata di altre modifiche e provato il tuo primo branch ma non riesce più ad applicare tali modifiche in maniera pulita. In questo caso puoi provare a ribasare il nuovo `origin/master` su quel branch, risolvere i conflitti per poi inviare di nuovo le tue modifiche: $ git checkout funzionalitaA $ git rebase origin/master $ git push –f miofork featureA -Questo riscrive la tua cronologia per farla diventare come quella di Figura 5-17. +Questo riscrive la tua cronologia per essere come quella di Figura 5-17. Insert 18333fig0517.png -Fgiura 5-17. La cronologia dei commit dopo il lavoro su funzionalitaA. +Fgiura 5-17. La cronologia ddopo il lavoro su funzionalitaA. -Dato che hai eseguito un rebase del ramo, devi specificare l'opzione `-f` per eseguire un push, per poter sostituire il ramo `funzionalitaA` sul server con un commit che non discende da esso. Un'alternativa potrebbe essere un push di questo nuovo lavoro verso un diverso branch sul server (chiamato ad esempio `funzionalitaAv2`). +Poiché hai eseguito un rebase del branch, per poter sostituire il branch `funzionalitaA` sul server con una commit che non discenda dallo stesso, devi usare l'opzione `-f` perché la push funzioni. Un'alternativa sarebbe fare una push di questo nuovo lavoro su un branch diverso (chiamato per esempio `funzionalitaAv2`). -Diamo un'occhiata ad un possibile scenario: il mantenitore ha guardato al tuo lavoro in un secondo ramo, e gradisce il concetto ma vorrebbe che tu cambiassi dei dettagli dell'implementazione. Potresti inoltre cogliere questa opportunità per basarti sul ramo `master` corrente. Crei un nuovo ramo basato sul corrente `origin/master`, sposti i cambiamenti di `funzionalitaB` qui, risolvi i conflitti, cambi l'implementazione, e poi esegui il push come un nuovo ramo: +Diamo un'occhiata a un altro scenario possibile: il mantenitore ha visto tuo lavoro nel secondo branch e gli piace il concetto ma vorrebbe che tu cambiassi un dettaglio dell'implementazione. Potresti cogliere l'occasione per ribasarti sul `master` corrente. Crea un nuovo branch basato sull'`origin/master` attuale, sposta lì le modifiche di `funzionalitaB`, risolvi gli eventuali conflitti, fai la modifica all'implementazione ed esegui la push del tutto su un nuovo branch: $ git checkout -b funzionalitaBv2 origin/master $ git merge --no-commit --squash funzionalitaB @@ -465,18 +462,18 @@ Diamo un'occhiata ad un possibile scenario: il mantenitore ha guardato al tuo la $ git commit $ git push miofork funzionalitaBv2 -L'opzione `--squash` prende tutto il lavoro nel ramo da unire e lo aggiunge come un singolo commit al ramo in cui sei. L'opzione `no-commit` dice a Git di non eseguire automaticamente il commit. Questo ti consente di aggiungere i cambiamenti da un altro ramo e poi eseguire altre modifiche prima di effettuare il nuovo commit. +L'opzione `--squash` prende tutto il lavoro dal branch da unire e lo aggiunge come una singola commit nel branch dove sei. L'opzione `--no-commit` dice a Git di non fare la commit automaticamente. Questo ti permette di aggiungere le modifiche di un altro branch e fare ulteriori modifiche prima di effettuare la nuovo commit. -Ora puoi inviare al mantenitore un messaggio dicendo che hai effettuato i cambiamenti richiesti e che può trovare nel ramo `funzionalitaBv2` (vedi Figura 5-18). +Ora puoi avvisare i mantenitori che hai effettuato le modifiche richieste e che possono trovarle nel branch `funzionalitaBv2` (vedi Figura 5-18). Insert 18333fig0518.png -Figura 5-18. La cronologia dei commit dopo il lavoro su funzionalitaBv2. +Figura 5-18. La cronologia dopo il lavoro su funzionalitaBv2. ### Grande Progetto Pubblico ### -Molti grandi progetti hanno definito delle procedure da seguire per poter inviare delle patch. Avrai bisogno di leggere le specifiche regole di ogni progetto, perchè queste potranno differire tra loro. Tuttavia, molti grandi progetti pubblici accettano patch tramite una mailing list degli sviluppatori, quindi tratterò ora un esempio di questo genere. +Molti grandi progetti hanno definito delle procedure per l'invio delle patch: dovrai leggere le specifiche di ciascun progetto, perchè saranno diverse. Tuttavia molti grandi progetti pubblici accettano patch tramite la mailing list degli sviluppatori, quindi tratterò ora questo caso. -Il flusso di lavoro è simile ai casi precedenti: crei un ramo per ognuna delle modifiche sulle quali intendi lavorare. La differenza sta in come invii tali modifiche al progetto. Invece di fare un tuo fork del progetto e di inviare le tue modifiche ad esso tramite push, crei una versione e-mail di ognuno dei commit e l invii tramite posta elettronica alla mailing list degli sviluppatori: +Il flusso di lavoro è simile al caso precedente: crei un branch per ognuna delle modifiche sulle quali intendi lavorare. La differenza sta nel modo in cui invii tali modifiche al progetto. Invece di fare un tuo fork del progetto e di inviare le tue modifiche con una push, crei una versione e-mail di ogni commit e invii il tutto per email alla mailing list degli sviluppatori: $ git checkout -b topicA $ (work) @@ -484,13 +481,13 @@ Il flusso di lavoro è simile ai casi precedenti: crei un ramo per ognuna delle $ (work) $ git commit -Ora hai due commit che vuoi inviare alla mailing list. Usi `git format-patch` per generare un file formato mbox che puoi inviare via e-mail alla mailing list. Il comando `git format-patch` trasforma ogni commit in un messaggio email il cui oggetto è formato dalla prima linea del messaggio del commit e il cui contenuto è il rimanente testo del commit più la patch delle modifiche. La cosa bella di tutto ciò è che applicando i commit da un'email si conservano tutte le informazioni in essi contenute in maniera appropriata, come vedrai meglio nella prossima sezione: +Ora hai due commit che vuoi inviare alla mailing list. Usi `git format-patch` per generare un file formato mbox che possa inviare via e-mail alla lista: questo trasforma ogni commit in un messaggio email il cui oggetto è la prima linea del messaggio della commit e il contenuto è dato dal resto del messaggio della commit più la patch delle modifiche. La cosa bella di tutto ciò è che, applicando le commit da un'email, vengono mantenute le informazioni delle commit, come vedrai meglio nella prossima sezione: $ git format-patch -M origin/master 0001-add-limit-to-log-function.patch 0002-changed-log-output-to-30-from-25.patch -Il comando `format-patch` visualizza i nomi dei file patch che vengono creati. Il parametro `-M` indica a Git di tener traccia dei file rinominati. I file infine hanno questo aspetto: +Il comando `format-patch` visualizza i nomi dei file delle patch che crea. Il parametro `-M` indica a Git di tener traccia dei file rinominati. I file alla fine avranno questo aspetto: $ cat 0001-add-limit-to-log-function.patch From 330090432754092d704da8e76ca5c05c198e71a8 Mon Sep 17 00:00:00 2001 @@ -520,11 +517,11 @@ Il comando `format-patch` visualizza i nomi dei file patch che vengono creati. I -- 1.6.2.rc1.20.g8c5b.dirty -Puoi anche modificare questi file patch per aggiungere maggiori informazioni per la mailing list che non vuoi vengano visualizzate all'interno del messaggio del commit. Se aggiungi del testo tra le righe contrassegnate da `---` e l'inizio della patch (ad esempio la riga `lib/simplegit.rb`), gli sviluppatori possono leggerlo ma esso verrà escluso dal messaggio del commit con il quale la patch verrà applicata. +Puoi anche modificare questi file per aggiungere maggiori informazioni per la mailing list che però non vuoi che vengano visualizzate all'interno del messaggio della commit. Se aggiungi del testo tra la riga con `---` e l'inizio della patch (ad esempio la riga `lib/simplegit.rb`), gli sviluppatori potranno leggerlo ma verrà escluso dal messaggio della commit una volta che la patch sarà applicata. -Per inviare le patch alla mailing list, puoi copiare ed incollare il file nel tuo programma di posta o inviare il tutto tramite un programma a linea di comando. Incollando il testo spesso si hanno dei problemi di formattazione, sopratutto con client di posta "intelligenti" che non preservano i caratteri di acapo e altri caratteri di spaziatura. Fortunatamente, Git fornisce uno strumento per aiutarti ad inviare le patch in modo corretto tramite IMAP, il che potrebbe risultare più semplice. Ti mostrerò come inviare una patch via Gmail, che è il client di posta che utilizzo io; puoi trovare le istruzioni dettagliate per diversi client di posta alla fine del documento `Documention/SubmittingPatches` presente nel codice sorgente di Git. +Per inviare le patch alla mailing list, puoi copiare ed incollare il file nel tuo programma di posta o inviare il tutto dalla riga di comando. Incollare il testo è spesso causa di problemi di formattazione, sopratutto con i client di posta "intelligenti" che non mantengono correttamente i caratteri di a-capo e altri caratteri di spaziatura. Fortunatamente Git fornisce uno strumento che ti aiuta a inviare correttamente le patch tramite IMAP, che potrebbe facilitarti il compito. Ti mostrerò come mandare una patch con Gmail perché è il client di posta che utilizzo, ma troverai istruzioni dettagliate per molti client di posta alla fine del documento `Documention/SubmittingPatches`, che trovi nel codice sorgente di Git. -Prima di tutto, devi configurare la sezione imap nel tuo file `~/.gitconfig`. Puoi settare ogni valore separatamente con una serie di comandi `git config` o aggiungerli manualmente al suo interno tramite un editor di testo. Alla fine il tuo file di configurazione dovrebbe essere più o meno così: +Prima di tutto devi configurare la sezione imap nel tuo file `~/.gitconfig`. Puoi configurare ogni parametro separatamente con una serie di comandi `git config` o scriverli direttamente con un editor di testo. Alla fine il tuo file di configurazione dovrebbe comunque essere più o meno così: [imap] folder = "[Gmail]/Drafts" @@ -534,7 +531,8 @@ Prima di tutto, devi configurare la sezione imap nel tuo file `~/.gitconfig`. Pu port = 993 sslverify = false -Se il tuo server IMAP non usa SSL, le ultime due righe probabilmente non ti saranno necessarie e il valore del campo host sarà `imap://` anzichè `imaps://`. Quando tutto ciò è configurato, puoi usare `git send-email` per inviare la serie di patch alla cartella "Bozze" del tuo server IMAP: +Se il tuo server IMAP non usa SSL, probabilmente le ultime due righe non ti saranno necessarie e il valore del campo host sarà `imap://` invece di `imaps://`. +Quando avrai configurato tutto, potrai usare `git send-email` per inviare la serie di patch alla cartella "Bozze" del tuo server IMAP: $ git send-email *.patch 0001-added-limit-to-log-function.patch @@ -544,7 +542,7 @@ Se il tuo server IMAP non usa SSL, le ultime due righe probabilmente non ti sara Who should the emails be sent to? jessica@example.com Message-ID to be used as In-Reply-To for the first email? y -Poi, Git produce alcune informazioni di log che figureranno più o meno così per ogni patch che stai inviando: +Per ciascuna patch che stai per inviare, Git produce alcune informazioni di log che appariranno più o meno così: (mbox) Adding cc: Jessica Smith from \line 'From: Jessica Smith ' @@ -561,53 +559,54 @@ Poi, Git produce alcune informazioni di log che figureranno più o meno così pe Result: OK -A questo punto, dovresti essere in grado di andare nella tua cartella delle bozze, cambiare il campo "A:" con la mailing list alla quale vuoi inviare la patch, aggiungere in copia il mantenitore del progetto o la persona responsabile per quella determinata sezione ed inviare il codice. +A questo punto, dovresti essere in grado di andare nella cartella bozze del tuo account, inserire nel campo "A:" la mailing list alla quale vuoi inviare la patch, magari aggiungendo in copia il mantenitore del progetto o la persona responsabile per quella determinata sezione e manda l'email. ### Sommario ### -Questa sezione ha coperto un certo numero di workflow comuni che è facile incontrare quando si ha a che fare con tipi diversi di progetti Git e ha introdotto un paio di nuovi strumenti che ti possono aiutare a gestire questo processo. Ora, vedrai come si lavora con l'altra faccia della medaglia: mantenere un progetto Git. Imparerai ad essere un dittatore benevolo o integration manager. +Questa sezione ha trattato alcuni workflow comuni che è facile incontrare quando si ha a che fare con progetti Git diversi e ha introdotto un paio di strumenti nuovi per aiutarti a gestire questo processo. Vedremo ora l'altra faccia della medaglia: mantenere un progetto Git. Imparerai ad essere un dittatore benevolo (_benevolent dictator_) o un manager d'integrazione (_integration manager_). ## Mantenere un Progetto ## -Oltre a sapere come contribuire ad un progetto in maniera effettiva, dovrai probabilmente sapere anche come mantenerne uno. Ciò consiste nell'accettare ed applicare le patch generate usando il comando `format-patch` e ricevute tramite e-mail oppure nell'integrare cambiamenti in rami dei repository che hai impostato come remote del tuo progetto. Sia che tu mantenga un repository o che tu voglia contribuire nel verificare le patch, devi sapere come eseguire il tuo compito in maniera chiara per gli altri contributori del progetto e sostenibile per te nel lungo periodo. +Oltre a sapere come contribuire ad un progetto in maniera effettiva, dovrai probabilmente sapere anche come mantenerne uno. Ciò consiste nell'accettare ed applicare le patch generate con il comando `format-patch` e ricevute tramite e-mail oppure nell'integrare le modifiche dei branch remoti che hai definito nel tuo progetto come remoti. Sia che mantenga un repository o che voglia contribuire verificando o approvando le patch, devi sapere come svolgere il tuo compito in modo che sia chiaro per gli altri contributori del progetto e sostenibile per te nel lungo periodo. -### Lavorare sui Topic Branches ### +### Lavorare coi branch per argomento ### -Quando pensi di integrare un nuovo lavoro, è generalmente una buona idea quella di provarlo in un "topic branch", ovvero un ramo temporaneo creato specificatamente per provare le modifiche introdotte dalla patch. In questo modo è semplice modificare la singola patch e, se questa non funziona, lasciarla intalterata fino a quando non avrai il tempo di tornarci nuovamente. Se crei un ramo con un nome semplice basato sull'argomento della patch, ad esempio `ruby_client`, ti sarà poi facile individuarlo nel caso tu debba lasciare temporaneamente il lavoro sulla patch per tornarci più avanti. Il mantenitore del progetto Git usa dare uno spazio dei nomi a questi rami, come ad esempio `sc/ruby_client`, dove `sc` sono le iniziali della persona che ha contribuito al lavoro. Come ricorderai, puoi creare un ramo partendo dal tuo ramo master con questi comandi: +Quando pensi di integrare un nuovo lavoro generalmente è una buona idea provarlo in un branch per argomento: un branch temporaneo, creato specificatamente per provare le modifiche dalla patch. In questo modo è semplice verificare la singola patch e, se questa non funziona, lasciarla intalterata fino a quando non avrai il tempo di ritornarci. Se crei un branch col nome dell'argomento della patch che proverai, per esempio `ruby_client` o qualcosa ugualmente descrittiva, ti sarà facile individuarlo nel caso tu debba temporaneamente lasciare il lavoro sulla patch per ritornarci più avanti. Il mantenitore del progetto Git usa dare uno gerarchia ai nomi di questi branch: come `sc/ruby_client`, dove `sc` sono le iniziali della persona che ha realizzato la patch. +Come ricorderai, puoi creare un branch partendo dal tuo master così: $ git branch sc/ruby_client master -Oppure, se vuoi anche passare al nuovo ramo immediatamente, puoi usare il comando `checkout -b`: +E, se vuoi passare immediatamente al nuovo branch, puoi usare il comando `checkout -b`: $ git checkout -b sc/ruby_client master -Ora sei pronto per aggiungere il lavoro a questo ramo e determinare se vuoi unirlo a uno dei rami del tuo progetto. +Ora sei pronto per aggiungere il lavoro a questo branch e decidere se vuoi unirlo a uno dei branch principali del tuo progetto. ### Applicare le patch da un'e-mail ### -Se ricevi via e-mail le patch che vuoi integrare nel tuo progetto, devi applicarle ognuna al relativo `topic branch` per poterle provare. Ci sono due modi per applicare una patch ricevuta via email: con `git apply` oppure con `git am`. +Se ricevi le patch via e-mail e le vuoi integrarle nel tuo progetto, devi prima applicarle per poterle giudicare. Ci sono due modi per applicare una patch ricevuta via email: con `git apply` o con `git am`. #### Applicare una patch con apply #### -Se hai ricevuto la patch da qualcuno che l'ha generata usando il comando `git diff` o un qualsiasi comando Unix `diff`, puoi applicarla usando `git apply`. Se per esempio la patch è stata salvata in `/tmp/patch-ruby-client.patch`, puoi applicarla con il seguente comando: +Se hai ricevuto la patch da qualcuno che l'ha generata usando il comando `git diff` o un qualsiasi comando Unix `diff`, puoi applicarla usando `git apply`. Se hai salvato la patch in `/tmp/patch-ruby-client.patch`, puoi applicarla così: $ git apply /tmp/patch-ruby-client.patch -Ciò modifica i file nella tua directory corrente. E' quasi uguale ad eseguire il comando `patch -p1` per applicare la patch, anche se questo comando è più paranoico e accetta meno corrispondenze di patch. Esso gestisce anche l'aggiunta, la rimozione e il cambio del nome dei file se ciò è descritto nel formato di `git diff`, cosa che il comando `patch` non fa. Infine, `git apply` segue il modello "applica tutto o rigetta tutto" dove vengono applicato tutte le modifiche oppure nessuna, mentre `patch` può applicarle anche solo parzialmente, lasciando la tua directory corrente in uno stato intermedio. `git apply` è in generale più paranoico di `patch`. Non creerà un commit per te: una volta eseguito, devi effettuare lo stage e il commit dei file manualmente. +Ciò modifica i file nella tua directory corrente. E' quasi uguale ad eseguire il comando `patch -p1` per applicare la patch, anche se questo comando è più paranoico e accetta meno corrispondenze di patch. Gstisce anche l'aggiunta, la rimozione e il cambio del nome dei file se ciò è descritto nel formato di `git diff`, cose che non fa `patch`. Infine `git apply` segue il modello "applica tutto o rigetta tutto" per cui o vengono applicato tutte le modifiche oppure nessuna, mentre `patch` può anche applicarne solo alcune, lasciando la tua directory corrente in uno stato intermedio. `git apply` è in generale molto più paranoico di `patch`. Non creerà una commit per te: una volta eseguito devi eseguire manualmente lo stage delle modifiche e farne la commit. -Puoi usare `git apply` anche per vedere se una patch può essere applicata in maniera pulita prima di applicarla veramente. Puoi eseguire `git apply --check` sulla patch: +Puoi anche usare `git apply` per verificare se una patch può essere applicata in maniera pulita, prima di applicarla veramente eseguendo `git apply --check` sulla patch: $ git apply --check 0001-seeing-if-this-helps-the-gem.patch error: patch failed: ticgit.gemspec:1 error: ticgit.gemspec: patch does not apply -Se non viene visualizzato alcun output, allora la patch può essere applicata in maniera pulita. Questo comando termina con un valore diverso da zero se il controllo fallisce, quindi puoi usarlo anche all'interno di uno script. +Se non viene visualizzato alcun output, allora la patch può essere applicata in maniera pulita. Questo comando restituisce un valore diverso da zero se la verifica fallisce, quindi puoi usarlo anche in uno script. -#### Applying a Patch with am #### +#### Applicare una patch con am #### -If the contributor is a Git user and was good enough to use the `format-patch` command to generate their patch, then your job is easier because the patch contains author information and a commit message for you. If you can, encourage your contributors to use `format-patch` instead of `diff` to generate patches for you. You should only have to use `git apply` for legacy patches and things like that. +Se il contributore è un utente Git ed è stato abbastanza bravo a usare il comando `format-patch` per generare la sua patch, allora il tuo lavoro sarà più facile perché la patch già contiene le informazioni sull'autore e un messaggio di commit. Se pouoi, per generare le patch per te, incoraggia i tuoi collaboratori ad utilizzare `format-patch` invece di `diff`. Dovresti dover usare solo `git apply` per le patch precedenti e altre cose del genere. -To apply a patch generated by `format-patch`, you use `git am`. Technically, `git am` is built to read an mbox file, which is a simple, plain-text format for storing one or more e-mail messages in one text file. It looks something like this: +Per applicare una patch generata con `format-patch`, userai `git am`. Tecnicamente `git am` è fatto per leggere un file mbox, che è un file piatto di puro testo per memorizzare uno o più messaggi email in un solo file. Assomiglia a questo: From 330090432754092d704da8e76ca5c05c198e71a8 Mon Sep 17 00:00:00 2001 From: Jessica Smith @@ -616,14 +615,14 @@ To apply a patch generated by `format-patch`, you use `git am`. Technically, `gi Limit log functionality to the first 20 -This is the beginning of the output of the format-patch command that you saw in the previous section. This is also a valid mbox e-mail format. If someone has e-mailed you the patch properly using git send-email, and you download that into an mbox format, then you can point git am to that mbox file, and it will start applying all the patches it sees. If you run a mail client that can save several e-mails out in mbox format, you can save entire patch series into a file and then use git am to apply them one at a time. +Questo è l'inizio dell'output del comando 'format-patch' che hai visto nella sezione precedente, ma è anche un formato valido per mbox per le email. Se qualcuno ti ha inviato la patch usando 'git send-email' e l'hai scaricata nel formato mbox, allora puoi selezionare il file mbox in 'git am' che inizierà ad applicare tutte le patch che trovi. Se hai un client di posta elettronica che ti permette di salvare più messaggi in un file mbox allora puoi salvare tutta una serie di patch in un singolo file e usare `git am` per applicarle tutte assieme. -However, if someone uploaded a patch file generated via `format-patch` to a ticketing system or something similar, you can save the file locally and then pass that file saved on your disk to `git am` to apply it: +Se invece qualcuno ha caricato una patch generata con `format-patch` su un sistema di ticket e tracciamento, puoi salvare localmente il file e passarlo a `git am` perché lo applichi: $ git am 0001-limit-log-function.patch Applying: add limit to log function -You can see that it applied cleanly and automatically created the new commit for you. The author information is taken from the e-mail’s `From` and `Date` headers, and the message of the commit is taken from the `Subject` and body (before the patch) of the e-mail. For example, if this patch was applied from the mbox example I just showed, the commit generated would look something like this: +Puoi vedere che ha applicato senza errori le modifiche e ha creato automaticamente una nuova commit per te. Le informazioni sull'autore e la data della commit vengono prese delle intestazioni `From` e `Date` dell'email, mentre il messaggio della commit è preso dal `Subject` e dal corpo dell'email che precede la patch. Se questa patch fosse stata applicata dall'esempio dell'mbox appena mostrato, la commit generata apparirebbe così: $ git log --pretty=fuller -1 commit 6c5e70b984a60b3cecd395edd5b48a7575bf58e0 @@ -636,9 +635,9 @@ You can see that it applied cleanly and automatically created the new commit for Limit log functionality to the first 20 -The `Commit` information indicates the person who applied the patch and the time it was applied. The `Author` information is the individual who originally created the patch and when it was originally created. +`Commit` indica chi ha applicato la patch e `CommitDate` quando. `Author` chi ha creato la patch originariamente e quando. -But it’s possible that the patch won’t apply cleanly. Perhaps your main branch has diverged too far from the branch the patch was built from, or the patch depends on another patch you haven’t applied yet. In that case, the `git am` process will fail and ask you what you want to do: +Ma è possibile che la patch non sia applicabile correttamente. Il tuo branch principale potrebbe essere cambiato troppo rispetto al branch da cui deriva la patch o che la patch dipenda da altre che non hai ancora applicato. In questo caso il processo di `git am` fallirà e ti chiederà cosa voglia fareprocess will fail and ask you what you want to do: $ git am 0001-seeing-if-this-helps-the-gem.patch Applying: seeing if this helps the gem @@ -649,14 +648,14 @@ But it’s possible that the patch won’t apply cleanly. Perhaps your main bran If you would prefer to skip this patch, instead run "git am --skip". To restore the original branch and stop patching run "git am --abort". -This command puts conflict markers in any files it has issues with, much like a conflicted merge or rebase operation. You solve this issue much the same way — edit the file to resolve the conflict, stage the new file, and then run `git am --resolved` to continue to the next patch: +Questo comando aggiunge dei marcatori di conflicco in ciascun file che presenti un problema, similmente a quanto avviene nelle operazioni di merge o rebase. E tu risolverai il problema allo stesso modo: modifica il file per risolvere il conflitto, mettilo nello stage ed esegui `git am --resolved` per continuare con la patch successiva: $ (fix the file) $ git add ticgit.gemspec $ git am --resolved Applying: seeing if this helps the gem -If you want Git to try a bit more intelligently to resolve the conflict, you can pass a `-3` option to it, which makes Git attempt a three-way merge. This option isn’t on by default because it doesn’t work if the commit the patch says it was based on isn’t in your repository. If you do have that commit — if the patch was based on a public commit — then the `-3` option is generally much smarter about applying a conflicting patch: +Se vuoi che Git provi a risolvere i conflitti più intelligentemente, puoi passargli l'opzione `-3`, e Git proverà a eseguire un merge a 3-vie. Quest'opzione non è attiva di default perché non funziona se la patch si basa su una commit che non hai nel tuo repository. Se invece hai quella commit (ovvero se la patch è basata su una commit pubblica) allora generalmente l'opzione `-3` è più intelligente nell'applicare una patch con conflitti: $ git am -3 0001-seeing-if-this-helps-the-gem.patch Applying: seeing if this helps the gem @@ -666,9 +665,9 @@ If you want Git to try a bit more intelligently to resolve the conflict, you can Falling back to patching base and 3-way merge... No changes -- Patch already applied. -In this case, I was trying to apply a patch I had already applied. Without the `-3` option, it looks like a conflict. +In questo caso sto cercando di applicare una patch che ho già applicato. Senza l'opzione `-3` sembrerebbe che ci sia un conflitto. -If you’re applying a number of patches from an mbox, you can also run the `am` command in interactive mode, which stops at each patch it finds and asks if you want to apply it: +Se stai applicando una serie di patch da un file mbox puoi eseguire il comando `am` anche in modalità interattiva, che si ferma ogni volta che incontra una patch per chiederti se vuoi applicarla: $ git am -3 -i mbox Commit Body is: @@ -677,38 +676,38 @@ If you’re applying a number of patches from an mbox, you can also run the `am` -------------------------- Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all -This is nice if you have a number of patches saved, because you can view the patch first if you don’t remember what it is, or not apply the patch if you’ve already done so. +Questo è utile se hai una serie di patch salvate, perché se non ti ricordi cosa sia puoi rivedere la patch, o non applicarla se l'hai già applicata. -When all the patches for your topic are applied and committed into your branch, you can choose whether and how to integrate them into a longer-running branch. +Quando tutte la patch per l'orgomento sono state applicate e committate nel tuo branch, puoi decidere se e come integrarle in un branch principale. -### Checking Out Remote Branches ### +### Scaricare branch remoti ### -If your contribution came from a Git user who set up their own repository, pushed a number of changes into it, and then sent you the URL to the repository and the name of the remote branch the changes are in, you can add them as a remote and do merges locally. +Se la contribuzione viene da un utente Git che ha un proprio repository su cui ha pubblicato una serie di modifiche e ti ha mandato l'indirizzo del repository e il nome del branch remoto in cui sono le stesse, puoi aggiungerlo come remoto e unirle localmente. -For instance, if Jessica sends you an e-mail saying that she has a great new feature in the `ruby-client` branch of her repository, you can test it by adding the remote and checking out that branch locally: +Se, per esempio, Jessica ti invia un'email dicendoti che nel branch `ruby-client` del suo repository ha sviluppato un'interessante funzionalità, tu puoi testarla aggiungendo il branch remoto e scaricarlo come uno localmente: $ git remote add jessica git://github.com/jessica/myproject.git $ git fetch jessica $ git checkout -b rubyclient jessica/ruby-client -If she e-mails you again later with another branch containing another great feature, you can fetch and check out because you already have the remote setup. +Se successivamente t'invia un'altra email con un altro branch che contenga un'altra funzionalità interessante tu puoi scaricarla più velocemente perché hai già configurato il repository remoto. -This is most useful if you’re working with a person consistently. If someone only has a single patch to contribute once in a while, then accepting it over e-mail may be less time consuming than requiring everyone to run their own server and having to continually add and remove remotes to get a few patches. You’re also unlikely to want to have hundreds of remotes, each for someone who contributes only a patch or two. However, scripts and hosted services may make this easier — it depends largely on how you develop and how your contributors develop. +Questa configurazione è molto utile se lavori molto con una persona. Se qualcuno produce una sola patch di tanto in tanto può essere più rapido accettarle per email, invece di chiedere a tutti di avere un proprio server pubblico e aggiungere in continuazione dei repository remoti per poche modifiche. Allo stesso tempo non vorrai centinaia di repository remoti per qualcuno che contribuisce solo con una patch o due. In ogni caso degli script o servizi di hostin possono rendere il tutto più semplice e principalmente dipende da come sviluppate tu e i tuoi contributori. -The other advantage of this approach is that you get the history of the commits as well. Although you may have legitimate merge issues, you know where in your history their work is based; a proper three-way merge is the default rather than having to supply a `-3` and hope the patch was generated off a public commit to which you have access. +L'altro vantaggio di questo approccio è che in aggiunta ricevi la cronologia delle commit. Sebbene tu possa avere problemi coi merge saprai su quale parte della tua cronologia si basi il lavoro dei contributori, il merge a 3-vie è il default e non richiede di specificare l'opzione `-3` e la patch potrebbe essere generata da una commit pubblica a cui tu abbia accesso. -If you aren’t working with a person consistently but still want to pull from them in this way, you can provide the URL of the remote repository to the `git pull` command. This does a one-time pull and doesn’t save the URL as a remote reference: +Se non lavori spesso con una persona ma vuoi comunque prendere le modifiche in questo modo puoi sempre passare l'URL del repository remoto al comando `git pull`. Questo farà una pull una tantum senza salvare l'URL come un riferimento remoto: $ git pull git://github.com/onetimeguy/project.git From git://github.com/onetimeguy/project * branch HEAD -> FETCH_HEAD Merge made by recursive. -### Determining What Is Introduced ### +### Determinare cos'è stato introdotto ### -Now you have a topic branch that contains contributed work. At this point, you can determine what you’d like to do with it. This section revisits a couple of commands so you can see how you can use them to review exactly what you’ll be introducing if you merge this into your main branch. +Hai un branch che contiene il lavoro di un contributore. A questo punto puoi decidere cosa farne. Questa sezione rivisita un paio di comandi così che tu possa vedere come usarli per revisionare con precisione cosa introdurrai se unissi queste modifiche al tuo branch principale. -It’s often helpful to get a review of all the commits that are in this branch but that aren’t in your master branch. You can exclude commits in the master branch by adding the `--not` option before the branch name. For example, if your contributor sends you two patches and you create a branch called `contrib` and applied those patches there, you can run this: +Spesso è utile revisionare le commit del branch che non sono ancora nel tuo master. Puoi escludere le commit di un branch aggiungendo l'opzione `--not` prima del nome del branch. Se un tuo contributore ti manda due patch e tu crei un branch chiamato `contrib` dove applichi le patch, puoi eseguire: $ git log contrib --not master commit 5b6235bd297351589efc4d73316f0a68d484f118 @@ -723,107 +722,107 @@ It’s often helpful to get a review of all the commits that are in this branch updated the gemspec to hopefully work better -To see what changes each commit introduces, remember that you can pass the `-p` option to `git log` and it will append the diff introduced to each commit. +Ricorda che puoi passare l'opzione `-p` a `git log` per vedere le modifiche di ciascuna commit, così che all'output aggiungerà le differenze introdotte da ciascuna commit. -To see a full diff of what would happen if you were to merge this topic branch with another branch, you may have to use a weird trick to get the correct results. You may think to run this: +Per vedere tutte le differenze che verrebbero applicate se unissi il branch attuale con un altro dovrai usare un trucchetto per vedere il risultato corretto. Potresti pensare di usare: $ git diff master -This command gives you a diff, but it may be misleading. If your `master` branch has moved forward since you created the topic branch from it, then you’ll get seemingly strange results. This happens because Git directly compares the snapshots of the last commit of the topic branch you’re on and the snapshot of the last commit on the `master` branch. For example, if you’ve added a line in a file on the `master` branch, a direct comparison of the snapshots will look like the topic branch is going to remove that line. +Ed effettivamente questo comando esegue una differenza, ma può essere causa di errori. Se il tuo branch `master` si fosse spostato in avanti rispetto a quando hai creato il branch vedrai risultati strani. Questo succede perché Git confronta direttamente l'istantanea ('snapshots') dell'ultima commit del branch con l'istantanea dell'ultima commit di `master`. Se, per esempio, hai aggiunto una riga in un file su `master` branch, un confronto diretto delle istantanee sembrerà indicare che il branch rimuova quella riga. -If `master` is a direct ancestor of your topic branch, this isn’t a problem; but if the two histories have diverged, the diff will look like you’re adding all the new stuff in your topic branch and removing everything unique to the `master` branch. +Se `master` è un antenato diretto del branch allora non sarà un problema, ma se le due cronologie si sono biforcate ti apparirà che stai aggiungendo tutte le cose nuove del tuo branch e rimuovendo tutto ciò che è solo in `master`. -What you really want to see are the changes added to the topic branch — the work you’ll introduce if you merge this branch with master. You do that by having Git compare the last commit on your topic branch with the first common ancestor it has with the master branch. +Quello che vuoi realmente vedere sono le modifiche aggiunte nel branch: il lavoro che effettivamente introdurrai se le unissi al master. Potrai ottenerlo facendo si che Git confronti l'ultima commit del branch col primo antenato comune con il branch master. -Technically, you can do that by explicitly figuring out the common ancestor and then running your diff on it: +Tecnicamente puoi farlo tu scoprendo l'antenato comune ed eseguendo quindi la diff: $ git merge-base contrib master 36c7dba2c95e6bbb78dfa822519ecfec6e1ca649 $ git diff 36c7db -However, that isn’t convenient, so Git provides another shorthand for doing the same thing: the triple-dot syntax. In the context of the `diff` command, you can put three periods after another branch to do a `diff` between the last commit of the branch you’re on and its common ancestor with another branch: +Questo però è scomodo e Git fornisce un modo più veloce per farlo: i tre punti. Nel contesto del comando `diff`, puoi usare tre punti dopo il nome di un branch per eseguire una `diff` tra l'ultima commit del branch in cui sei e l'antenato comune con un altro branch: $ git diff master...contrib -This command shows you only the work your current topic branch has introduced since its common ancestor with master. That is a very useful syntax to remember. +Questo comando ti mostra solo le modifiche introdotte dal branch attuale a partire dall'antenato comune con master. Questa sintassi è molto utile da ricordare. -### Integrating Contributed Work ### +### Integrare il lavoro dei contributori ### -When all the work in your topic branch is ready to be integrated into a more mainline branch, the question is how to do it. Furthermore, what overall workflow do you want to use to maintain your project? You have a number of choices, so I’ll cover a few of them. +Quando tutto il lavoro del tuo branch è pronto per essere integrato in un branch principale nasce il prblema di come farlo. Inoltre, quale workflow vuoi usare per mantenere il tuo progetto? Hai una serie di scelte e ne tratterò alcune. -#### Merging Workflows #### +#### I workflow per il merge #### -One simple workflow merges your work into your `master` branch. In this scenario, you have a `master` branch that contains basically stable code. When you have work in a topic branch that you’ve done or that someone has contributed and you’ve verified, you merge it into your master branch, delete the topic branch, and then continue the process. If we have a repository with work in two branches named `ruby_client` and `php_client` that looks like Figure 5-19 and merge `ruby_client` first and then `php_client` next, then your history will end up looking like Figure 5-20. +Un workflow semplice unisce le modifiche nel branch `master`. In questo scenario hai un `master` che contiene del codice stabile. Quando hai del lavoro in un branch funzionale che sia tuo o di un contributore e di cui tu abbia già verificato il buon funzionamento, lo unisci al master, cancelli il branch e così via. Se abbiamo un repository che abbia delle modifiche in due branch funzionali chiamati `ruby_client` e `php_client` questo apparirà come in Figura 5-19 e se unissimo prima `ruby_client` e poi `php_client` allora la nostra cronologia apparirà come quella in Figura 5-20. Insert 18333fig0519.png -Figure 5-19. History with several topic branches. +Figura 5-19. Cronologia con branch funzionali multipli. Insert 18333fig0520.png -Figure 5-20. After a topic branch merge. +Figura 5-20. Dopo l'unione dei branch funzionali. -That is probably the simplest workflow, but it’s problematic if you’re dealing with larger repositories or projects. +Probabilmente questo è il workflow più semplice, ma è anche problematico se stai lavorando con repository o progetti grandi. -If you have more developers or a larger project, you’ll probably want to use at least a two-phase merge cycle. In this scenario, you have two long-running branches, `master` and `develop`, in which you determine that `master` is updated only when a very stable release is cut and all new code is integrated into the `develop` branch. You regularly push both of these branches to the public repository. Each time you have a new topic branch to merge in (Figure 5-21), you merge it into `develop` (Figure 5-22); then, when you tag a release, you fast-forward `master` to wherever the now-stable `develop` branch is (Figure 5-23). +Se hai più sviluppatori o lavori in un progetto grande, probabilmente vorrai usare un ciclo d'unione a due fasi. In questo scenario hai due branch principali, `master` e `develop`, e hai deciso che `master` viene aggiornato esclusivamente con un rilascio molto stabile e tutto il codice nuovo viene integrato nel branch `develop`. Condividi regolarmente entrambi i branch su un repository pubblico e ogni volta che hai un nuovo branch funzionale da integrare (Figura 5-21) lo fai in `develop` (Figura 5-22), quindi taggi il rilascio e fai un `fast-forward` di `master` al punto in cui `develop` è stabile (Figura 5-23). Insert 18333fig0521.png -Figure 5-21. Before a topic branch merge. +Figura 5-21. Prima dell'unione del branch funzionale. Insert 18333fig0522.png -Figure 5-22. After a topic branch merge. +Figura 5-22. Dopo l'unione del branch funzionale. Insert 18333fig0523.png -Figure 5-23. After a topic branch release. +Figura 5-23. Dopo il rilascio di un branch funzionale. -This way, when people clone your project’s repository, they can either check out master to build the latest stable version and keep up to date on that easily, or they can check out develop, which is the more cutting-edge stuff. -You can also continue this concept, having an integrate branch where all the work is merged together. Then, when the codebase on that branch is stable and passes tests, you merge it into a develop branch; and when that has proven itself stable for a while, you fast-forward your master branch. +In questo modo quando qualcuno clona il repository del tuo progetto, questi può scaricare il master per avere l'ultima versione stabile e tenersi aggiornato, o scaricare la versione di sviluppo che contiene le ultime cose. +Puoi estendere questo concetto avendo un branch in cui integri tutto il nuovo lavoro. Quando il codice di questo branch è stabile e ha passato tutti i test lo unisci al branch di sviluppo e quando questo ha dimostrato di essere stabile per un po', fai un _fast-forward_ del tuo master. -#### Large-Merging Workflows #### +#### Workflow per unioni grandi #### -The Git project has four long-running branches: `master`, `next`, and `pu` (proposed updates) for new work, and `maint` for maintenance backports. When new work is introduced by contributors, it’s collected into topic branches in the maintainer’s repository in a manner similar to what I’ve described (see Figure 5-24). At this point, the topics are evaluated to determine whether they’re safe and ready for consumption or whether they need more work. If they’re safe, they’re merged into `next`, and that branch is pushed up so everyone can try the topics integrated together. +Il progetto Git ha quattro branch principali: `master`, `next`, e `pu` (aggiornamenti suggeriti - `proposed updates`) per il nuovo lavoro, e `maint` per la manutenzione dei backport. Quando un contributore introduce una modifica, questa viene raccolta nei branch funzionali del repository del mantenitore in modo simile a quanto ho già descritto (vedi Figura 5-24). A questo punto le modifiche vengono valutate per deteminare se sono sicure e pronte per essere utilizzate o se hanno bisogno di ulteriore lavoro. Se sono sicure vengono unite in `next` e questo branch viene condiviso perché chiunque possa provarle tutte assieme. Insert 18333fig0524.png -Figure 5-24. Managing a complex series of parallel contributed topic branches. +Figura 5-24. Gestire una serie complessa di branch funzionali paralleli. -If the topics still need work, they’re merged into `pu` instead. When it’s determined that they’re totally stable, the topics are re-merged into `master` and are then rebuilt from the topics that were in `next` but didn’t yet graduate to `master`. This means `master` almost always moves forward, `next` is rebased occasionally, and `pu` is rebased even more often (see Figure 5-25). +Se la funzione ha bisogno di ulteriori modifiche viene unita invece in `pu` e quando viene ritenuta realmente stabile viene unita di nuovo su `master` e viene ricostruita dal codice che era in `next`, ma non è ancora promossa su `master`. Questo significa che `master` va quasi sempre avanti, `next` raramente è ribasato e `pu` viene ribasato molto spesso (see Figura 5-25). Insert 18333fig0525.png -Figure 5-25. Merging contributed topic branches into long-term integration branches. +Figura 5-25. Unire branch di contribuzione nei branch principali. -When a topic branch has finally been merged into `master`, it’s removed from the repository. The Git project also has a `maint` branch that is forked off from the last release to provide backported patches in case a maintenance release is required. Thus, when you clone the Git repository, you have four branches that you can check out to evaluate the project in different stages of development, depending on how cutting edge you want to be or how you want to contribute; and the maintainer has a structured workflow to help them vet new contributions. +Quando un branch funzionale viene finalmente unito in `master` viene anche rimosso dal repository. Il progetto Git ha anche un branch `maint` che è un fork dell'ultima release per fornire patch a versioni precedenti nel caso sia necessaria un rilascio di manutenzione. Quindi, quando cloni il repository di Git puoi usare quattro branch per valutare il progetto in stadi diversi dello sviluppo, a seconda che tu voglia le ultime funzionalità o voglia contribuire, e il mantenitore ha strutturato il workflow in modo da favorire nuove contribuzioni. -#### Rebasing and Cherry Picking Workflows #### +#### Workflow per il rebase e lo _cherry pick_ #### -Other maintainers prefer to rebase or cherry-pick contributed work on top of their master branch, rather than merging it in, to keep a mostly linear history. When you have work in a topic branch and have determined that you want to integrate it, you move to that branch and run the rebase command to rebuild the changes on top of your current master (or `develop`, and so on) branch. If that works well, you can fast-forward your `master` branch, and you’ll end up with a linear project history. +Altri mantenitori preferiscono ribasare o usare lo _cherry-pick_ aggiungere i contributi nel loro branch master, piuttosto che unirli, per mantenere una cronologia il più lineare possibile. Quando hai delle modifiche in un branch funzionale e hai deciso che vuoi integrarle, ti sposti su quel branch ed esegui il comando _rebase_ per replicare le modifiche del tuo master attuale (o `develop` e così via). Se queste funzionano, allora fai un _fast-forward_ del tuo `master` e ti ritroverai con un progetto dalla cronologia lineare. -The other way to move introduced work from one branch to another is to cherry-pick it. A cherry-pick in Git is like a rebase for a single commit. It takes the patch that was introduced in a commit and tries to reapply it on the branch you’re currently on. This is useful if you have a number of commits on a topic branch and you want to integrate only one of them, or if you only have one commit on a topic branch and you’d prefer to cherry-pick it rather than run rebase. For example, suppose you have a project that looks like Figure 5-26. +L'altro modo per spostare il lavoro dei contributori da un branch all'altro è di usare lo _cherry-pick_. Lo _cherry-pick_ in Git è come una rebase per una commit singola. Prende la patch introdotta nella commit e prova a riapplicarla sul branch dove sei. Questo è utile se hai molte commit in un branch funzionale e vuoi integrarne solo alcune o se hai un'unica commit in un branch funzionale e preferisci usare lo `cherry-pick` piuttosto che ribasare. Immagina di avere un progetto che sembri quello di Figura 5-26. Insert 18333fig0526.png -Figure 5-26. Example history before a cherry pick. +Figura 5-26. Cronologia prima dello _cherry pick_. -If you want to pull commit `e43a6` into your master branch, you can run +Se vuoi introdurre la commit `e43a6` nel tuo master puoi eseguire $ git cherry-pick e43a6fd3e94888d76779ad79fb568ed180e5fcdf Finished one cherry-pick. [master]: created a0a41a9: "More friendly message when locking the index fails." 3 files changed, 17 insertions(+), 3 deletions(-) -This pulls the same change introduced in `e43a6`, but you get a new commit SHA-1 value, because the date applied is different. Now your history looks like Figure 5-27. +Che replica le stesse modifiche introdotte in `e43a6`, ma produce una nuova commit con un suo SHA-1 differente perché le date sono diverse. La tua cronologia ora assomiglia a quella in Figura 5-27. Insert 18333fig0527.png -Figure 5-27. History after cherry-picking a commit on a topic branch. +Figura 5-27. Cronologia dopo lo _cherry-picking_ dal branch funzionale. -Now you can remove your topic branch and drop the commits you didn’t want to pull in. +Puoi ora eliminare il branch funzionale e cancellare le commit che non vuoi integrare. -### Tagging Your Releases ### +### Tagga i tuoi rilasci ### -When you’ve decided to cut a release, you’ll probably want to drop a tag so you can re-create that release at any point going forward. You can create a new tag as I discussed in Chapter 2. If you decide to sign the tag as the maintainer, the tagging may look something like this: +Quando hai deciso di eseguire un rilascio probabilmente vorrai anche taggarla, così che tu possa ricrearla in qualsiasi momento nel futuro. Puoi aggiungere un nuovo tag come discusso nel Capitolo 2. Se vuoi firmare il tag in quanto mantenitore, il tag potrebbe apparire come il seguente: $ git tag -s v1.5 -m 'my signed 1.5 tag' You need a passphrase to unlock the secret key for user: "Scott Chacon " 1024-bit DSA key, ID F721C45A, created 2009-02-09 -If you do sign your tags, you may have the problem of distributing the public PGP key used to sign your tags. The maintainer of the Git project has solved this issue by including their public key as a blob in the repository and then adding a tag that points directly to that content. To do this, you can figure out which key you want by running `gpg --list-keys`: +Se firmi il tuo tag potresti avere il problema di distribuire la chiave PGP usata per firmarlo. Il mantenitore del progetto Git lo ha risolto includendo le chiavi dei mantenitori come un blob sul repository e aggiungendo quindi un tag che vi punti direttamente. Per farlo dovrai identificare la chiave che vuoi esportare eseguendo `gpg --list-keys`: $ gpg --list-keys /Users/schacon/.gnupg/pubring.gpg @@ -832,49 +831,49 @@ If you do sign your tags, you may have the problem of distributing the public PG uid Scott Chacon sub 2048g/45D02282 2009-02-09 [expires: 2010-02-09] -Then, you can directly import the key into the Git database by exporting it and piping that through `git hash-object`, which writes a new blob with those contents into Git and gives you back the SHA-1 of the blob: +Potrai quindi importare la chiave direttamente nel database di Git esportandola e mettendola in pipe con `git hash-object`, che scrive in Git un nuovo blob con il suo contenuto e ti restituisce l'hash SHA-1: $ gpg -a --export F721C45A | git hash-object -w --stdin 659ef797d181633c87ec71ac3f9ba29fe5775b92 -Now that you have the contents of your key in Git, you can create a tag that points directly to it by specifying the new SHA-1 value that the `hash-object` command gave you: +Ora che hai importato il contenuto della tua chiave in Git puoi creare un tag che vi punti direttamente, specificando l'SHA-1 appena ottenuto: $ git tag -a maintainer-pgp-pub 659ef797d181633c87ec71ac3f9ba29fe5775b92 -If you run `git push --tags`, the `maintainer-pgp-pub` tag will be shared with everyone. If anyone wants to verify a tag, they can directly import your PGP key by pulling the blob directly out of the database and importing it into GPG: +Se esegui `git push --tags` verrà condiviso con tutti il tag `maintainer-pgp-pub`. Se qualcuno volesse verificare il tag potrà farlo importando la tua chiave PGP scaricando il blob dal database e importandolo in GPG: $ git show maintainer-pgp-pub | gpg --import -They can use that key to verify all your signed tags. Also, if you include instructions in the tag message, running `git show ` will let you give the end user more specific instructions about tag verification. +Può quindi usare la chiave per verificare tutti i tag che hai firmato. Inoltre, se aggiungi delle istruzioni nel messaggio del tag, eseguendo `git show ` darai all'utente finale maggiori informazioni specifiche su come verificare il tag. -### Generating a Build Number ### +### Generare un numero di build ### -Because Git doesn’t have monotonically increasing numbers like 'v123' or the equivalent to go with each commit, if you want to have a human-readable name to go with a commit, you can run `git describe` on that commit. Git gives you the name of the nearest tag with the number of commits on top of that tag and a partial SHA-1 value of the commit you’re describing: +Poiché Git non usa una numerazione incrementale come 'v123' o un equivalente associato a ciascuna commit, se vuoi un nome per una commit che sia intellegibile, puoi usare il comando `git describe` su quella commit. Git restituirà il nome del tag più vicino assieme al numero di commit successivi e una parte dell'SHA-1 della commit che vuoi descrivere: $ git describe master v1.6.2-rc1-20-g8c5b85c -This way, you can export a snapshot or build and name it something understandable to people. In fact, if you build Git from source code cloned from the Git repository, `git --version` gives you something that looks like this. If you’re describing a commit that you have directly tagged, it gives you the tag name. +In questo modo puoi esportare un'istantanea o una build echiamarla in modo che le persone possano capire. Se infatti fai una build di Git dai sorgenti clonati dal repository di Git repository, `git --version` ti restituirà qualcosa che gli assomigli. Se vuoi descrivere una commit che hai taggato, Git ti darà il nome del tag. -The `git describe` command favors annotated tags (tags created with the `-a` or `-s` flag), so release tags should be created this way if you’re using `git describe`, to ensure the commit is named properly when described. You can also use this string as the target of a checkout or show command, although it relies on the abbreviated SHA-1 value at the end, so it may not be valid forever. For instance, the Linux kernel recently jumped from 8 to 10 characters to ensure SHA-1 object uniqueness, so older `git describe` output names were invalidated. +Il comando `git describe` predilige i tag annotati (i tags creati con`-a` o `-s`) e quindi i tag dei rilasci dovrebbero essere creati in questo modo se usi `git describe`, per assicurarsi che le commit vengano denominate correttamente quando vengono descritte. Puoi usare questa stringa per i comandi `checkout` o `show`, sebbene il basarsi sull'SHA-1 abbreviato potrebbe renderla non valida per sempre. Per esempio, recentemente il kernel di Linux è passato recentemente da 8 a 10 caratteri per garantire l'unicità degli SHA-1 abbreviati, e quindi gli output precedenti di `git describe` non sono più validi. -### Preparing a Release ### +### Pronti per il rilascio ### -Now you want to release a build. One of the things you’ll want to do is create an archive of the latest snapshot of your code for those poor souls who don’t use Git. The command to do this is `git archive`: +Vuoi ora rilasciare una build. Una delle cose che vorrai fare sarà creare un archivio con l'ultima istantanea del tuo codice per quelle anime dannate che non usano Git. Il comando è `git archive`: $ git archive master --prefix='project/' | gzip > `git describe master`.tar.gz $ ls *.tar.gz v1.6.2-rc1-20-g8c5b85c.tar.gz -If someone opens that tarball, they get the latest snapshot of your project under a project directory. You can also create a zip archive in much the same way, but by passing the `--format=zip` option to `git archive`: +Quando qualcuno aprirà questo tarball, troverà l'ultima versione del tuo progetto nella directory `project`. Allo stesso modo puoi creare un archivio zip passando l'opzione `--format=zip` a `git archive`: $ git archive master --prefix='project/' --format=zip > `git describe master`.zip -You now have a nice tarball and a zip archive of your project release that you can upload to your website or e-mail to people. +Ora hai un tarball e uno zip del rilascio del tuo progetto che puoi caricare sul tuo sito o inviare per email. -### The Shortlog ### +### Lo Shortlog ### -It’s time to e-mail your mailing list of people who want to know what’s happening in your project. A nice way of quickly getting a sort of changelog of what has been added to your project since your last release or e-mail is to use the `git shortlog` command. It summarizes all the commits in the range you give it; for example, the following gives you a summary of all the commits since your last release, if your last release was named v1.0.1: +È il momento di inviare un'email alla lista di persone che vogliono sapere cosa succede nel tuo progetto. Un modo piacevole per produrre una specie di changelog delle modifiche dall'ultimo rilascio o dall'ultima email è usando il comando `git shortlog`, che riassume tutte le commit nell'intervallo dato. L'esempio seguente produce il sommario di tutte le commit dall'ultimo rilascio, assumento che lo abbia chiamato v1.0.1: $ git shortlog --no-merges master --not v1.0.1 Chris Wanstrath (8): @@ -891,8 +890,8 @@ It’s time to e-mail your mailing list of people who want to know what’s happ Version bump to 1.0.2 Regenerated gemspec for version 1.0.2 -You get a clean summary of all the commits since v1.0.1, grouped by author, that you can e-mail to your list. +Ottieni un sommario pulito di tutte le commit dalla v1.0.1, raggruppate per autore che puoi quindi inviare per email alla tua lista. -## Summary ## +## Sommario ## -You should feel fairly comfortable contributing to a project in Git as well as maintaining your own project or integrating other users’ contributions. Congratulations on being an effective Git developer! In the next chapter, you’ll learn more powerful tools and tips for dealing with complex situations, which will truly make you a Git master. +Dovresti sentirti ora a tuo agio nel contribuire a progetti Git, tanto quanto mantenere il tuo progetto o integrare i contributi di altri utenti. Congratulazione per essere un vero sviluppatore Git! Nel prossimo capitolo imparerai alcuni strumenti molto potenti e suggerimenti per affrontare situazione complesse che ti faranno diventare un maestro di Git. diff --git a/it/06-git-tools/01-chapter6.markdown b/it/06-git-tools/01-chapter6.markdown index d22624086..50559d39e 100644 --- a/it/06-git-tools/01-chapter6.markdown +++ b/it/06-git-tools/01-chapter6.markdown @@ -1,39 +1,22 @@ -# Git Tools # +# Strumenti di Git # -Fin'ora sono stati imparati la maggior parte dei comandi giornalieri a i -workflow che potrebbero essere necessari a gestire e mantenere un repository Git -per il controllo del codice sorgente. -Sono state compiute le attività di base per il tracciamento e il commit dei -file, ed è stato sfruttato il potere della *staging area* e argomenti leggeri il -*branching* (ramificazione) e il *merge*. +Finora hai imparato la maggior parte dei comandi d’uso quotidiani e i flussi di lavoro che devi conoscere per gestire o mantenere un repository Git per i tuoi sorgenti. Hai eseguito le attività di base per tracciare e committare i file, hai sfruttato il potere dell' *area di assemblamento* e le diramazioni (*branch*) e le unioni (*merge*) leggere. -Ora verrà esplorato un numero di cose veramente potenti che Git può fare che non -vengono necessariamente usate di base quotidianamente ma che potrebbero servire -ad un certo punto. +Ora vedremo una serie di cose molto potenti di Git che potresti non usare quotidianamente, ma di cui a un certo punto potresti averne bisogno. ## Selezione della revisione ## -Git permette di specificare determinati *commit* o una serie di *commit* in -diversi modi. -Non sono necessariamente evidenti ma può essere d'aiuto conoscerli. +Git ti permette di specificare una o più *commit* in diversi modi. Non sono sempre ovvi, ma è utile conoscerli. -### Singola revisione ### +### Singole versioni ### -E' possibile ovviamente riferirsi a un *commit* tramite l'hash SHA-1 che viene -dato, ma ci sono modi più alla portata degli umani per riferirsi ai *commit*. -Questa sezione delinea i diversi modi con cui ci si può riferire ad un singolo -commit. +Puoi fare riferimento a una singola commit usando l’hash SHA-1 attribuito, ma ci sono altri metodi più amichevoli per fare riferimento a una *commit*. Questa sezione delinea i modi con cui ci si può riferire a una singolo commit. ### SHA breve ### -Git è abbastanza intelligente da capire a quale *commit* ci si riferisce se si -fornisce i primi caratteri, purché il codice SHA-1 sia di almeno quattro -caratteri e univoco - solo un oggetto nel *repository* corrente inizia con quel -SHA-1 parziale. +Git è abbastanza intelligente da capire a quale *commit* ti riferisci se scrivi i primi caratteri purché il codice SHA-1 sia di almeno quattro caratteri e sia univoco: ovvero che uno solo degli oggetti nel *repository* inizi con quel SHA-1. -Per esempio, per vedere uno specifico *commit*, supponiamo che venga eseguito un -comando 'git log' e venga identificato un *commit* dove sono state aggiunte -certe funzionalità: +Per vedere per esempio una specifica *commit*, immagina di eseguire 'git log' e trovi la *commit* dove sono state aggiunte determinate funzionalità: $ git log commit 734713bc047d87bf7eac9674765ae793478c50d3 @@ -55,122 +38,74 @@ certe funzionalità: added some blame and merge stuff -In questo caso, scegliamo '1c002dd....' Se viene eseguito 'git show' su quel -*commit*, i seguenti comandi sono equivalenti (assumendo che le versioni più -corte siano univoche): +In questo caso scegli '1c002dd....'. Se vuoi eseguire 'git show' su quella *commit*, i seguenti comandi sono equivalenti (assumendo che le versioni più brevi siano univoche): $ git show 1c002dd4b536e7479fe34593e72e6c6c1819e53b $ git show 1c002dd4b536e7479f $ git show 1c002d -Git riesce a capire una corta, univoca abbreviazione del valore SHA-1. Se viene -passato '--abbrev-commit' al comando 'git-log', l'*output* userà valori più -corti ma li manterrà unici; in maniera predefinita utilizza sette caratteri ma -se necessario ne userà di più per mantenere il codice SHA-1 univoco: +Git riesce a capire un valore SHA-1 intero da uno corto, abbreviato. Se usi l’opzione '--abbrev-commit' col comando 'git-log', l'*output* userà valori più corti ma garantirà che siano unici: di default usa sette caratteri ma ne userà di più se sarà necessario per mantenere l’univocità del valore SHA-1: $ git log --abbrev-commit --pretty=oneline ca82a6d changed the version number 085bb3b removed unnecessary test code a11bef0 first commit -Generalmente, da otto a dieci caratteri sono più che sufficienti per essere -univoci all'interno di un progetto. -Uno dei progetti Git più grandi, il kernel Linux, inizia a necessitare 12 -caratteri, dei 40 possibili, per rimanere univoco. +Da otto a dieci caratteri sono, generalmente, più che sufficienti per essere univoci all'interno di un progetto. Uno dei progetti Git più grandi, il kernel di Linux, inizia a necessitare 12 caratteri, dei 40 possibili, per essere univoco. ### Una breve nota su SHA-1 ### -Un sacco di gente si preoccupa ad un certo punto che, per una qualche casualità, -potrebbe avere due oggetti nel proprio *repository* che abbiano lo stesso hash -SHA-1. Cosa accadrebbe a quel punto? - -Se capita di fare il *commit* di un oggetto che ha lo stesso SHA-1 di un oggetto -precedente nel proprio *repository*, Git noterà il precedente oggetto già -presente nel database Git e lo riterrà già scritto. -Provando ad ottenere informazioni su quell'oggetto nuovamente ad un certo punto, -verranno sempre restituiti i dati del primo oggetto. - -Ad ogni modo, è necessario essere consapevoli di quanto ridicolmente improbabile -sia questo scenario. Il codice SHA-1 riassunto è di 20 bytes o 160 bits. Il -numero casuale di oggetti necessari per assicurare un 50% di una singola -collisione è di circa 2^80 (la formula per determinare la probabilità di -collisione è `p = (n(n-1)/2) * (1/2^160))`. 2^80 è 1.2 x 10^24 o un milione di -miliardi di miliardi. E' 1,200 volte il numero di granelli di sabbia sulla -terra. - -Ecco un esempio per dare un'idea di cosa ci vorrebbe per ottenere una collisione -SHA-1. Se tutti i 6.5 miliardi di esseri umani sulla Terra stessero -programmando, e ogni secondo, ognuno stesse producendo codice che fosse -equivalente all'intera storia del kernel Linux (1 milione di oggetti Git) e se -lo stesse caricando su un enorme *repository* Git, ci vorrebbero 5 anni per -contenere abbastanza oggetti in quel *repository* da avere il 50% di possibilità -di una singola collisione di oggetti SHA-1. Esiste una probabilità più alta che -ogni membro del team venga attaccato e ucciso dai lupi in situazioni -indipendenti durante la stessa notte. - -### Riferimenti al *branch* ### - -La strada più diretta per specificare un *commit* richiede che punti ad un -riferimento di un *branch*. A quel punto potrebbe essere usato il nome del -*branch* in qualsiasi comando Git che richiede un oggetto *commit* o un valore -SHA-1. Per esempio, se si vuole mostrare l'ultimo oggetto *commit* di un -*branch*, i seguenti comandi sono equivalenti, ammesso che il *branch* 'topic1' -punti a 'ca82a6d': +Molte persone si preoccupa che a un certo punto, in modo del tutto casuale, ci possano essere due oggetti nel tuo *repository* che abbiano lo stesso SHA-1. Cosa succederebbe? + +Se dovessi committare un oggetto che abbia lo stesso hash SHA-1 di un altro oggetto che sia già nel tuo repository, Git troverà l'altro oggetto già nel database di Git e lo considererà già scritto. Se in seguito vorrai scaricare quest'ultimo ogetto, otterrai sempre le informazioni del più vecchio. + +Dovresti comunque essere consapevole che questo sia uno scenario molto improbabile. Il codice SHA-1 è di 20 bytes o 160 bits. Il numero di oggetti casuali necessari perché ci sia la probabilità del 50% di una singola collisione è di circa 2^80 (la formula per determinare la probabilità di collisione è `p = (n(n-1)/2) * (1/2^160)`). 2^80 è 1.2 x 10^24 ovvero 1 milione di miliardi di miliardi. È 1.200 volte il numero di granelli di sabbia sulla terra. + +Ecco un esempio per dare un'idea di cosa ci vorrebbe per ottenere una collisione SHA-1. Se tutti i 6.5 miliardi di esseri umani sulla Terra programmassero e, ogni secondo, ognuno scrivesse codice che sia equivalente all'intera cronologia del kernel Linux (1 milione di oggetti Git) e ne facesse la push su un enorme *repository* Git, ci vorrebbero 5 anni per contenere abbastanza oggetti in quel *repository* per avere il 50% di possibilità di una singola collisione di oggetti SHA-1. Esiste una probabilità più alta che ogni membro del tuo gruppo di sviluppo, in incidenti non correlati venga attaccato e ucciso da dei lupi nella stessa notte. + +### Riferimenti alle diramazioni ### + +Il modo più diretto per specificare una *commit* è avere una diramazione (*branch* in inglese) che vi faccia riferimento, che ti permetterebbe di usare il nome della diramazione in qualsiasi comando Git che richieda un oggetto *commit* o un valore SHA-1. Se per esempio vuoi vedere l'ultima *commit* di una diramazione, i comandi seguenti sono equivalenti (supponendo che la diramazione 'topic1' punti a 'ca82a6d'): $ git show ca82a6dff817ec66f44342007202690a93763949 $ git show topic1 -Se si vuole vedere a quale specifico SHA un *branch* punta, o se si vuole vedere -a cosa si riduce ognuno di questi esempi in termini di SHA, si può usare un -*plumbing tool* di Git chiamato 'rev-parse'. Nel Capitolo 9 ci sono più informazioni -sui *plumbing tool*; sostanzialmente, 'rev-parse' esiste per operazioni di basso -livello e non è concepito per essere usato in operazioni quotidiane. Comunque, -può essere d'aiuto a volte quanto c'è bisogno di vedere cosa succede realmente. -A quel punto si può lanciare 'rev-parse' sul proprio *branch*. +Se vuoi vedere a quale SHA specifico punti una diramazione, o se vuoi vedere a quali SHA puntino questi esempi, puoi usare il comando 'rev-parse' di Git, che fa parte dei comandi sottotraccia (*plumbing* in inglese) . Nel Capitolo 9 trovi maggiori informazioni sui comandi sottotraccia ma, brevemente, 'rev-parse' esiste per operazioni di basso livello e non è concepito per essere usato nelle operazioni quotidiane. Può comunque essere d'aiuto quando hai bisogno di vedere cosa sta succedendo davvero. Qui puoi quindi eseguire 'rev-parse' sulla tua diramazione. $ git rev-parse topic1 ca82a6dff817ec66f44342007202690a93763949 -### RefLog ### +### Nomi brevi dei riferimenti ### -Una delle cose che Git fa mentre si lavora è tenere un reflog - un log sui -riferimenti di *HEAD* e *branch* degli ultimi mesi. +Una delle cose che Git fa dietro le quinte è aggiornare il registro dei riferimenti (*reflog* in inglese), che registra la posizione dei tuoi riferimenti HEAD e delle diramazione su cui hai lavorato negli ulti mesi. -E' possibile vedere il reflog usando il comando 'git reflog': +Puoi consultare il registro con il comando 'git reflog': $ git reflog - 734713b... HEAD@{0}: commit: fixed refs handling, added gc auto, updated - d921970... HEAD@{1}: merge phedders/rdocs: Merge made by recursive. - 1c002dd... HEAD@{2}: commit: added some blame and merge stuff - 1c36188... HEAD@{3}: rebase -i (squash): updating HEAD - 95df984... HEAD@{4}: commit: # This is a combination of two commits. - 1c36188... HEAD@{5}: rebase -i (squash): updating HEAD - 7e05da5... HEAD@{6}: rebase -i (pick): updating HEAD - -Ogni volta che il *branch* è aggiornato, Git registra l'informazione in questa -lista temporanea. Si possono specificare anche *commit* più vecchi. Se si vuole -vedere il quinto valore precedente della *HEAD* del proprio *repository*, si può -usare il riferimento '@{n}' che si vede nel *output* di reflog: + 734713b HEAD@{0}: commit: fixed refs handling, added gc auto, updated + d921970 HEAD@{1}: merge phedders/rdocs: Merge made by recursive. + 1c002dd HEAD@{2}: commit: added some blame and merge stuff + 1c36188 HEAD@{3}: rebase -i (squash): updating HEAD + 95df984 HEAD@{4}: commit: # This is a combination of two commits. + 1c36188 HEAD@{5}: rebase -i (squash): updating HEAD + 7e05da5 HEAD@{6}: rebase -i (pick): updating HEAD + +Ogni volta che una diramazione viene aggiornata per qualsiasi ragione, Git memorizza questa informazione in questa cronologia temporanea. E puoi anche specificare *commit* più vecchie. Se vuoi vedere la cronologia a partire dalla quintultima commit a partire dalla *HEAD* del tuo *repository*, puoi usare il riferimento '@{n}' che vedi nel *output* del registro: $ git show HEAD@{5} -Si può anche usare questa sintassi per vedere dove era un *branch* una certa -quantità di tempo fa. Per esempio, per vedere dov'era il 'master' *branch* ieri, -si può scrivere: +Puoi anche usare questa sintassi per vedere dov'era una diramazione a una certa data. Se vuoi vedere, per esempio, dov'era ieri la diramazione 'master' puoi scrivere: $ git show master@{yesterday} -Questo mostra dove era il *branch* ieri. Questa tecnica funziona solo per i dati -che sono ancora nel *reflog*, non è possibile usarla per vedere *commit* più -vecchi di qualche mese. +Che mostra dov'era ieri la diramazione. Questa tecnica funziona solo per i dati che sono ancora nel registri e non puoi quindi usarla per vedere *commit* più vecchie di qualche mese. -Per vedere le informazioni del *reflog* formattate come il '*git log*', si può -lanciare il comando 'git log -g': +Per vedere le informazioni del registro formattate come l’output di `git log`, puoi eseguire il comando `git log -g`: $ git log -g master commit 734713bc047d87bf7eac9674765ae793478c50d3 Reflog: master@{0} (Scott Chacon ) - Reflog message: commit: fixed refs handling, added gc auto, updated + Reflog message: commit: fixed refs handling, added gc auto, updated Author: Scott Chacon Date: Fri Jan 2 18:32:33 2009 -0800 @@ -184,32 +119,24 @@ lanciare il comando 'git log -g': Merge commit 'phedders/rdocs' -E' importante notare che l'informazione del *reflog* è strettamente locale - è -un log di cosa è stato fatto nel proprio *repository*. I riferimenti non saranno -uguali nella copia del *repository* tenuta da qualcun altro. -Lanciare 'git show HEAD@{2.months-ago}' funzionerà solo se il progetto è stato -clonato almeno due mesi fa - se è stato clonato cinque minuti prima non verrà -restituito alcun risultato. +E' importante notare che l'informazione del registro è solamente locale: è un registro di ciò che hai fatto nel tuo *repository*. I riferimenti non saranno uguali sui cloni degli altri. Appena dopo aver clonato un *repository* il tuo registro sarà vuoto perché non è successo ancora nulla nel tuo *repository*. Potrai eseguire 'git show HEAD@{2.months.ago}' solo se hai clonato il progetto almeno due mesi fa: se è stato clonato cinque minuti fa non otterrai nessun risultato. -### Riferimenti di discendenza ### +### Riferimenti ancestrali ### -L'altro modo per specificare un *commit* è attraverso la sua discendenza. Se -viene posizionato un `^` alla fine di un riferimento, Git lo interpreta come il -genitore di quel determinato *commit*. -Supponiamo che si guardi la lista delle modifiche effettuate nel progetto: +L'altro modo principale per specificare una *commit* è attraverso i suoi ascendenti. Se metti un `^` alla fine di un riferimento, Git lo risolve interpretandolo come il padre padre di quella determinata *commit*. +Immagina di vedere la cronologia del tuo progetto: $ git log --pretty=format:'%h %s' --graph * 734713b fixed refs handling, added gc auto, updated tests * d921970 Merge commit 'phedders/rdocs' - |\ + |\ | * 35cfb2b Some rdoc changes * | 1c002dd added some blame and merge stuff - |/ + |/ * 1c36188 ignore *.gem * 9b29157 add open3_detach to gemspec file list -E' possibile vedere il precedente *commit* specificando `HEAD^`, che significa -"il genitore di HEAD": +Puoi quindi vedere la *commit* precedente specificando `HEAD^`, che significa "l'ascendente di HEAD": $ git show HEAD^ commit d921970aadf03b3cf0e71becdaab3147ba71cdef @@ -219,11 +146,7 @@ E' possibile vedere il precedente *commit* specificando `HEAD^`, che significa Merge commit 'phedders/rdocs' -Si può anche specificare un numero dopo `^` - per esempio, `d921970^2` significa -"il secondo genitore di d921870." Questa sintassi è utile per fare il *merge* di -*commit* che hanno più di un genitore. -Il primo genitore è il *branch* dove ci si trova al momento del *merge*, e il -secondo è il *commit* sul *branch* di cui è stato fatto il *merge*: +Puoi specificare anche un numero dopo la `^`: per esempio `d921970^2` significa "il secondo ascendente di d921870." Questa sintassi è utile solo per incorporare delle *commit* che hanno più di un ascendente. Il primo ascendente è la diramazione dove ti trovi al momento dell'incorporamento, e il secondo è la *commit* sulla diramazione da cui hai fatto l'incorporamento: $ git show d921970^ commit 1c002dd4b536e7479fe34593e72e6c6c1819e53b @@ -239,12 +162,7 @@ secondo è il *commit* sul *branch* di cui è stato fatto il *merge*: Some rdoc changes -Un altro modo per specificare la discendenza è `~`. Anche questo si riferisce al -primo genitore, quindi `HEAD~` e `HEAD^` sono equivalenti. La differenza si nota -quando viene specificato un numero. -`HEAD~2` significa "il primo genitore del primo genitore", o "il nonno" - -attraversa i primi genitori il numero di volte specificato. Per esempio, nella -lista mostrata precedentemente, `HEAD~3` sarebbe +Un altro modo di specificare un riferimento ancestrale è la `~`. Questo si riferisce anche al primo ascendente, quindi `HEAD~` e `HEAD^` sono equivalenti. La differenza diventa evidente quando specifichi un numero. `HEAD~2` significa "il primo ascendente del primo ascendente", o "il nonno”: attraversa i primi ascendenti il numero di volte specificato. Per esempio, nella cronologia precedente, `HEAD~3` sarebbe $ git show HEAD~3 commit 1c3618887afb5fbcbea25b7c013f4e2114448b8d @@ -253,8 +171,7 @@ lista mostrata precedentemente, `HEAD~3` sarebbe ignore *.gem -Potrebbe essere anche scritto come `HEAD^^^`, che è sempre il primo genitore del -primo genitore del primo genitore: +Che può essere scritto anche come `HEAD^^^` che, di nuovo, è sempre il primo genitore del primo genitore del primo genitore: $ git show HEAD^^^ commit 1c3618887afb5fbcbea25b7c013f4e2114448b8d @@ -263,6 +180,965 @@ primo genitore del primo genitore: ignore *.gem -E' possibile anche combinare queste sintassi - si può prendere il secondo -genitore del precedente riferimento (assumendo che si tratti di un *merge -commit*) usando `HEAD~3^2`, e così via. +È anche possibile combinare queste sintassi: puoi prendere il secondo genitore del riferimento precedente (assumendo che si tratti di una commit d'incorporamento) usando `HEAD~3^2`, e così via. + +### Intervalli di commit ### + +Ora che sai come specificare singole commit, vediamo come specificare intervalli di commit. Ciò è particolarmente utile per gestire le tue diramazioni: se ne hai molte puoi usare gli intervalli per rispondere a domande come “cosa c’è in questa diramazione che non ho ancora incorporato?” + +#### Due punti #### + +Il modo più comune per specificare un intervallo è con i due punti che, praticamente, chiede a Git di risolvere l’intervallo tra commit che sia raggiungibile da una commit, ma non dall’altra. Immaginiamo di avere la cronologia dell’immagine 6-1 + +Insert 18333fig0601.png +Figure 6-1. Esempio di cronologia per la selezione di intervalli. + +Vuoi vedere cosa sia nella tua diramazione sperimentale che non sia ancora stato incorporato nella master: puoi chiedere a Git di mostrarti solo il registro delle commit con `master..experiment`: questo significa “tutte le commit raggiungibili da experiment che non lo siano da master”. Affinché questi esempi siano sintetici ma chiari, invece del registro effettivo di Git, userò le lettere degli oggetti commit del diagramma: + + $ git log master..experiment + D + C + +Se volessi invece vedere il contrario, ovvero tutte le commit in `master` che non siano in `experiment`, puoi invertire i nomi dei branch: `experiment..master` ti mostra tutto ciò che è in `master` e che non sia raggiungibile da `experiment`: + + $ git log experiment..master + F + E + +Questo è utile se vuoi mantenere aggiornata la diramazione `experiment` e sapere cosa stai per incorporare. Un’altro caso in cui si usa spesso questa sintassi è quando stai per condividere delle commit verso un repository remoto: + + $ git log origin/master..HEAD + +Questo comando mostra tutte le commit della tua diramazione che non sono in quella `master` del tuo repository remoto `origin`. Se esegui `git push` quando la tua diramazione attuale è associata a `origin/master`, le commit elencate da `git log origin/master..HEAD` saranno quelle che saranno inviate al server. +Puoi anche omettere una delle parti della sintassi, e Git assumerà che sia HEAD. Per esempio puoi ottenere lo stesso risultato dell’esempio precedente scrivendo `git log origin/master..`: Git sostituisce la parte mancante con HEAD. + +#### Punti multipli #### + +La sintassi dei due punti è utile come la stenografia, ma potresti voler specificare più di due branch per indicare la tua revisione, per vedere le commit che sono nelle varie diramazioni che non siano in quella attuale. Git ti permette di farlo sia con `^` che con l’opzione `--not` prima di ciascun riferimento del quale vuoi vedere le commit raggiungibili. Quindi questi tre comandi sono equivalenti: + + $ git log refA..refB + $ git log ^refA refB + $ git log refB --not refA + +Questo è interessante, perché con questa sintassi puoi specificare più di due riferimenti nella tua richiesta, cosa che non puoi fare con i due punti. Se per esempio vuoi vedere tutte le commit che siano raggiungibili da `refA` o da `refB` ma non da `refC` puoi usare una delle seguenti alternative: + + $ git log refA refB ^refC + $ git log refA refB --not refC + +Questo produce un sistema di revisione molto potente che dovrebbe aiutarti a capire cosa c’è nelle tue diramazioni. + +#### Tre punti #### + +L’ultima sintassi per la selezione di intervalli è quella dei tre punti, che indica tutte le commit raggiungibili da uno qualsiasi dei riferimenti ma non da entrambi. Rivedi la cronologia delle commit nella Figura 6-1. +Se vuoi vedere cosa ci sia nel `master` o in `experiment` ma non i riferimenti comuni, puoi eseguire + + $ git log master...experiment + F + E + D + C + +Che ti mostra l’output normale del `log` mostrando solo le informazioni di quelle quattro commit nell'ordinamento cronologico normale. + +Un'opzione comunemente usata in questi casi con il comando `log` è il parametro `--left-right`, che mostra da che lato dell'intervallo si trovi ciascuna commit dell’intervallo selezionato, che rende le informazioni molto più utili: + + $ git log --left-right master...experiment + < F + < E + > D + > C + +Con questi strumenti puoi dire facilmente a Git quale o quali commit vuoi ispezionare. + +## Assemblaggio interattivo ## + +Git viene distribuito con un paio di script che rendono più semplice l'uso della riga di comando. In questo capitolo vedremo alcuni comandi interattivi che possono aiutarti a modellare le tue commit perché includano solo determinate combinazioni di parti dei file. Questi strumenti sono molto utili se modifichi molti file tutti assieme e poi decidi che vuoi distribuire le modifiche in più commit puntuali, piuttosto che un'unica grossa commit confusa. In questo modo puoi fare che le tue commit separino logicamente le tue modifiche e possano essere facilmente revisionate dagli altri sviluppatori con cui lavori. +Se esegui `git add` con le opzioni `-i` o `--interactive`, Git entrerà nella modalità interattiva, mostrandoti qualcosa del genere: + + $ git add -i + staged unstaged path + 1: unchanged +0/-1 TODO + 2: unchanged +1/-1 index.html + 3: unchanged +5/-1 lib/simplegit.rb + + *** Commands *** + 1: status 2: update 3: revert 4: add untracked + 5: patch 6: diff 7: quit 8: help + What now> + +Come vedi, questo comando mostra una vista della tua area di assemblaggio molto diversa: sono le stesse informazioni che otterà con il comando `git status`, ma in maniera più succinta e con più informazioni. Sulla sinistra mostra le modifiche che stai assemblando e quelle non ancora assemblate sulla destra. + +Dopo questa sezione c'è quella dei Comandi. Qui puoi fare una serie di cose, incluso assemblare file, disassemblarli, assemblare alcune parti dei file, aggiungere file non ancora tracciati e vedere le differenze con ciò che è già stato assemblato. + +### Assemblare e disassemblare file ### + +Se digiti `2` o `u` alla richiesta `What now>`, lo script ti chiederà quale file vuoi assemblare: + + What now> 2 + staged unstaged path + 1: unchanged +0/-1 TODO + 2: unchanged +1/-1 index.html + 3: unchanged +5/-1 lib/simplegit.rb + Update>> + +Per assemblare i file TODO e index.html, puoi digitare i numeri: + + Update>> 1,2 + staged unstaged path + * 1: unchanged +0/-1 TODO + * 2: unchanged +1/-1 index.html + 3: unchanged +5/-1 lib/simplegit.rb + Update>> + +L'asterisco (`*`) vicino a ogni file, significa che è stato selezionato per essere assemblato. Se premi INVIO alla richiesta `Update>>`, Git assembla tutto ciò che è stato selezionato: + + Update>> + updated 2 paths + + *** Commands *** + 1: status 2: update 3: revert 4: add untracked + 5: patch 6: diff 7: quit 8: help + What now> 1 + staged unstaged path + 1: +0/-1 nothing TODO + 2: +1/-1 nothing index.html + 3: unchanged +5/-1 lib/simplegit.rb + +Ora puoi vedere che i file TODO e index.html sono assemblati e simplegit.rb non lo è ancora. Se ora vuoi disassemblare il file TODO, devi digitare `3` o `r` (come `revert` - annullare): + + *** Commands *** + 1: status 2: update 3: revert 4: add untracked + 5: patch 6: diff 7: quit 8: help + What now> 3 + staged unstaged path + 1: +0/-1 nothing TODO + 2: +1/-1 nothing index.html + 3: unchanged +5/-1 lib/simplegit.rb + Revert>> 1 + staged unstaged path + * 1: +0/-1 nothing TODO + 2: +1/-1 nothing index.html + 3: unchanged +5/-1 lib/simplegit.rb + Revert>> [enter] + reverted one path + +Rivedendo lo stato di Git, puoi vedere che hai disassemblato il file TODO: + + *** Commands *** + 1: status 2: update 3: revert 4: add untracked + 5: patch 6: diff 7: quit 8: help + What now> 1 + staged unstaged path + 1: unchanged +0/-1 TODO + 2: +1/-1 nothing index.html + 3: unchanged +5/-1 lib/simplegit.rb + +Per vedere le differenze di ciò che hai assemblato puoi digitare `6` o `d` (come differenza). Ti mostrerà un elenco dei tuoi file assemblati, e potrai selezionare quelli di cui vuoi vedere le modifiche assemblate. Questo fa la stessa cosa del comando `git diff --cached`: + + *** Commands *** + 1: status 2: update 3: revert 4: add untracked + 5: patch 6: diff 7: quit 8: help + What now> 6 + staged unstaged path + 1: +1/-1 nothing index.html + Review diff>> 1 + diff --git a/index.html b/index.html + index 4d07108..4335f49 100644 + --- a/index.html + +++ b/index.html + @@ -16,7 +16,7 @@ Date Finder + +

...

+ + - + + + +