html текст
All interests
  • All interests
  • Design
  • Food
  • Gadgets
  • Humor
  • News
  • Photo
  • Travel
  • Video
Click to see the next recommended page
Like it
Don't like
Add to Favorites

Come Git Some!

Прочитай эту статью, или твои исходники умрут!

Каждый разработчик ошибается минимум дважды. Первый раз — когда выбирает себе профессию, надеясь при этом стать звездой и переплюнуть успех Facebook. А второй — когда забивает болт на true методики коллективной разработки и рвет на себе волосы во время очередного краха исходников. Серебряной пули для первой ошибки еще не придумали, а вот вторая проблема решается просто. Главное — созреть и окончательно мигрировать на профессиональные системы управления версиями.

Почему архивы — это плохо?

Я всегда удивлялся, когда видел, как хорошие программисты перед внесением изменений в файл проекта тупо архивируют его, присваивая в качестве имени что-то вроде cart.php.150220131500.zip. Нетрудно догадаться, что сакральный смысл этой конструкции подразумевает имя сценария (cart.php) и дату создания архива. Я такое встречаю достаточно часто и скажу по большому секрету, что на заре своей карьеры поступал точно так же. Все изменилось, когда я умудрился потерять кучу рабочего кода, банально перепутав архив.

Досадная ошибка молодости заставила меня обратить внимание на специализированные системы управления версиями. Буду откровенным — переход дался непросто. Поначалу трудно заставить себя выполнять «лишние» действия… лишь спустя время (обычно период адаптации длится в районе месяца) начинаешь удивляться: «Как я раньше работал по-другому?»

Недолгая дружба с SVN

Не подумай, что мы ходим сказать про SVN что-то плохое. Просто лично мне не понравилось, что для работы над проектом я должен иметь постоянное соединение с SVN-сервером. Этот минус особенно проявляется при отсутствии постоянного рабочего места. В таких случаях сервер обязан быть доступен извне, а мобильное рабочее место подразумевает хорошее соединение с инетом. Нет качественного коннекта — здравствуйте, тормоза при очередном получении изменений.

Вторым существенным минусом для меня стала гора служебного мусора. Меня дико бесило, что SVN пихает в каждую директорию проекта скрытую папку с кучей служебных файлов. В последних версиях эту проблему вроде как решили, но этот путь слегка затянулся.

Знакомьтесь, это Git!

Нередко разрушения и бесконечные споры провоцируют рождение поистине удивительных вещей. Случилось это и с Git. Все начиналось довольно просто и, конечно же, не без участия законодателя моды королевства Open Source — Linux. С самого первого релиза (1991 год) разработка кода ядра выполнялась по старинке: путем приема патчей от «населения» и архивирования предыдущих версий. Объемы кода ядра, внушающее ужас число разработчиков и современные тенденции не могли не внести корректив в этот процесс. В 2002 году проект разработки ядра перекочевал на проприетарную распределенную систему управления версиями BitKeeper от BitMover Inc.

К счастью, в сотрудничестве с компанией BitMover Inc. произошел разлад, вынудивший компанию забрать право бесплатного использования их продукта. Этот неприятный инцидент подстегнул Линуса Торвальдса с компанией девелоперов на создание собственной системы управления версиями. Ребята хотели разработать надежное решение, обладающее высокой скоростью работы и упрощающее командную разработку. В 2005 году все эти хотелки вылились в первую версию Git.

Git с самого начала пришелся по душе разработчикам. Буквально сразу его взяли на вооружение крупные open source проекты (Drupal, Linux). Однако главный всплеск популярности произошел после запуска специализированного хостинга Git-проектов - GitHub. Сегодня львиная доля опенсорсных проектов размещаются именно там.

Как работает Git

В целом Git представляется простым продуктом, но первое знакомство с ним зачастую проходит не совсем гладко. Причина заключается в непонимании основополагающих принципов работы.

Первым делом нужно усвоить главное правило: не нужно пытаться подгонять термины и знания, полученные при работе с другими подобными продуктами.

Идеология Git в корне отличается от SVN (как пример), и все попытки натянуть одну теорию на другую, скорее всего, завершатся путаницей.

Для начала давай вспомним, как данные хранятся в системах типа SVN. Если отбросить умные слова из толстых книг, то можно сказать, что система просто хранит файлы и цепочку изменений к ним. Схематично это выглядит так:

ФАЙЛ -> Изменение № 1 -> Изменение № 2 -> Изменение № 3

В Git все происходит совершенно иначе. Он не пытается хранить лишь изменения отдельного файла. Вместо этого он делает слепки (копии) абсолютно всех входящих в проект файлов на текущий момент. Если файл не изменился, то вместо копии создастся ссылка на предыдущую копию (или оригинал). Таким образом, разработчик всегда работает с одним набором файлов, просто их содержимое меняется от условий. Очередной слепок создается на этапе фиксации изменений. На схеме это отображается так:

ВЕРСИЯ 1      Версия 2
Файл № 1      Файл № 1 (А) (файл изменился)
Файл № 2      Файл № 2 (просто ссылка, файл не менялся)
Файл № 3      Файл № 3 (A) (файл изменился)

Чем Git лучше других?

Одно из самых важных преимуществ Git — децентрализованность. Смотри сам, Git, в отличие от альтернативных систем управления версиями, не требуется постоянного соединения с сервером. Все файлы проекта хранятся локально (!), поэтому ты можешь работать над кодом в любом месте и в любое время.

Отсутствие необходимости коннекта с сервером избавляет от различных сетевых тормозов. У меня нередко возникали ситуации, когда требовалось подключиться к рабочему SVN-серверу из командировки посредством GPRS-соединения. Это была настоящая каторга!

Наличие полных локальных копий проекта сразу решает проблему с резервированием данных. Каждый разработчик обладает полной копией всех файлов, и при необходимости из нее можно поднять оригинал. Падение сервера с удаленным репозиторием превращается в не самую большую проблему.

Выделять сильные стороны Git можно бесконечно долго, но не упомянуть про киллер-фичу однозначно нельзя. Я говорю про ветки. Это самая сильная функция, и на первых порах от нее реально сносит голову. Никто не запрещает создавать в своем репозитории кучу веток и постоянно переключаться между ними или объединять несколько веток в одну!

Немного теории

Одна из главных сущностей мира Git — различные состояния файлов. Каждый файл, входящий в состав проекта, может находиться в одном из трех состояний:

  • измененный — состояние присваивается сразу после редактирования, файл находится в нем до момента фиксации;
  • зафиксированный — данное состояние файл получает после сохранения в локальной базе Git;
  • подготовленный — измененный файл, подготовленный для следующего коммита.

Отдельного разговора заслуживает структура каждого проекта, работающего под управлением Git. Условно ее можно разделить на три составляющие: служебная директория (git directory), рабочая директория (working directory) и область подготовленных файлов (staging area). Служебная директория git представляет собой хранилище метаданных и базу данных всех объектов проекта. Ты можешь увидеть ее, если заглянешь в любой клонированный или созданный тобой репозиторий. Там ты обязательно увидишь скрытую папку с именем «.git».

Рабочая директория — это папка, в которой хранятся файлы твоего проекта. Все ее содержимое представляет собой копию определенной версии проекта.

Под областью подготовленных файлов подразумевается обычный файл, расположенный в служебной директории и содержащий информацию об изменениях, которые войдут в следующий коммит.

От слов к делу

Втиснуть всю необходимую теорию в одну часть статьи просто нереально, поэтому предлагаю приступить к практике и рассматривать возникшие вопросы по ходу дела. Сразу хочу сказать, что мы не будем затрагивать поднятие локального Git-хостинга (это ты сможешь сделать сам, прочитав во врезке про дистрибутив GitLite). Лучше потренируемся на сервисе Bitbucket. Почему именно на нем, а не на великом GitHub?

Во-первых, Bitbucket ничуть не уступает ему по возможностям. А во-вторых, он позволяет совершенно бесплатно создавать приватные репозитории для небольших команд. За эту же возможность на GitHub придется платить 200 рублей в месяц.

Готовим инструменты

Мы договорились, что в качестве хостинга своих проектов будем использовать Bitbucket, поэтому потрудись сразу создать в нем учетную запись. Как только твой аккаунт будет готов, сразу беги на goo.gl и сливай последнюю версию дистрибутива Git. По указанной ссылке лежат дистрибутивы под Windows. Если твоя родная площадка — Linux, то установить актуальную версию дистрибутива ты сможешь при помощи apt-get.

Настройка Git

После установки Git необходимо произвести пару настроек — установить свое имя (именно оно будет отображаться в коммитах) и e-mail. Для ввода опций запусти консоль Git Bash и выполни следующие команды:

$ git config --global user.name “spider_net” # Задаем имя пользователя. Отображается в коммитах
$ git config --global user.email “antonov.igor.khv@gmail.com” # Задаем e-mail пользователя

Локальный репозиторий

Создать репозиторий мы можем одним из двух способов: клонировать существующий или создать новый. Первый способ гораздо проще, поэтому начнем с него.

Для начала создай где-нибудь у себя на винте директорию, в которую будем помещать все git-проекты. Я создал такую на диске E: и обозвал ее «test-git». Открой окно консоли (Git Bash), если успел его уже закрыть, и установи в качестве текущей директории папку, которую только что создал:

$ cd E:/test-git

С этим разобрались. Теперь зайди на GitHub (не из консоли, а с помощью браузера) и выбери абсолютно любой проект, на котором мы потренируемся в создании клонов. Я не стал мучить себя выбором и в качестве первого подопытного выбрал Drupal (https://github.com/drupal/drupal). На странице с каждым открытым репозиторием имеется строка ввода, в которой указан полный путь к репозиторию. В случае с Drupal это будет https://github.com/drupal/drupal.git. Скопируй его в буфер обмена, а затем возвращайся в консоль и вбей в нее:

$ git clone https://github.com/drupal/drupal.git drupal7

Этой командой мы сообщили о своем желании клонировать репозиторий Drupal в директорию drupal7. После выполнения операции в директории test-git появится новый каталог, содержащий исходные коды популярной системы управления контентом Drupal.

Клонируем Drupal
Клонируем Drupal

Клонирование существующих репозиториев выполняется просто, но и создать репозиторий для существующего проекта ничуть не сложней.

Возьми любой свой старый проект (язык программирования особой роли не играет) и помести его в нашу общую для всех проектов папку test-git. Для демонстрации я взял один из своих проектов на C#, над которым мы когда-то трудились с моим другом, и поместил в папку kaskoCalc.

Теперь нам требуется сообщить Git о своем желании сотрудничать. В этот момент будет создана служебная директория (помнишь о скрытой папке .git?), набитая разными файлами. Данная операция выполняется при помощи команды git init. Вводи ее в консоли (предварительно не забудь переместиться в папку с тестовым проектом), а после загляни в директорию проекта. В нем должна появиться скрытая папка .git.

Однако этого действия недостаточно для включения всех файлов проекта под версионный контроль. Наша задача добавить все файлы в индекс и выполнить фиксацию изменений. Набери в консоли несколько команд:

$ git add * # Подготавливаем все файлы
$ git commit -m “source of my project” # Выполняем фиксацию    

Удаленный репозиторий

Создавать локальные репозитории для своих проектов мы научились. Мы также убедились, что в этом нет ничего сложного. Теперь давай посмотрим, как перенести наш локальный репозиторий на хостинг Git-проектов Bitbucket. Если ты еще не создал в нем учетную запись, самое время сделать это.

Заходи в личный кабинет и создай новый репозиторий (Create repository). Тебя попросят ввести имя репозитория (name), описание (description), уровень доступа (access level), тип репозитория (git/mercurial) и язык программирования, на котором выполнен проект. Для своего проекта в качестве имени я указал kaskocalc, установил уровень доступа private (с репозиторием сможем работать только мы) и в поле выбора языка программирования остановился на C#.

Создание нового репозитория в Bitbucket
Создание нового репозитория в Bitbucket

Выполнив эту нехитрую операцию, возвращайся к консоли и введи несколько команд:

# Добавляем алиас для удаленного репозитория
# Это позволит нам не писать длиннющие адреса, ведущие на Bitbucket
# Следующая команда создаст алиас kaskocalc для пустого репозитория kaskocalc.git
$ git remote add kaskocalc https://guavastudio@bitbucket.org/guavastudio/kaskocalc.git
# Выполняем отправку файлов из локального репозитория, в ветку master удаленного
$ git push kaskocalc master

После отправки последней команды ты увидишь приглашение ввести пароль. Вбивай сюда пароль от аккаунта в Bitbucket. Если не возникло никаких ошибок, то все файлы твоего проекта мигрируют в удаленный репозиторий.

Локальное хранилище мигрировало в Bitbucket
Локальное хранилище мигрировало в Bitbucket
README расположился в разделе Overview
README расположился в разделе Overview

Собственный GitHub

Поюзав сервисы вроде Bitbucket и GitHub, ты рано или поздно задумаешься: «А существует ли возможность развернуть собственный Git-сервер?» Оказывается, сделать это совсем не сложно. Достаточно установить на свой сервер какой-нибудь дистрибутив Linux и развернуть на нем приложение GitLab. Это бесплатная альтернатива проектам вроде GitHub. После установки ты также получишь функциональный веб-интерфейс (позволяет выполнять административные функции, управлять правами доступа, просматривать коммиты и так далее) и возможность получить доступ к репозиториям через SHH, HTTPS. Система устанавливается буквально за пару команд.

Разбираемся с ветками

Теперь посмотрим, как работать с одной из самых крутых фишек Git — ветвлением. Я не преувеличиваю важности и крутости этой функции. Она действительно шикарна и позволяет разработчикам комфортно работать над множеством задач, не прибегая к созданию нескольких копий исходников всего проекта. Благодаря развитой модели ветвления Git завоевал свою неслыханную популярность и продолжает покорять сердца разработчиков.

Что же в этой модели такого особенного и почему она так эффективна? Частично на этот вопрос я ответил выше: разработчику не требуется делать копию всех файлов проекта. Работа продолжается в такой же директории, с теми же исходниками, но Git будет знать, что это новая ветка, а значит, сможет корректно зафиксировать изменения и при желании вернуться на другую ветку. Вообще, при работе над проектами под управлением Git применяется негласное правило: каждую задачу нужно решать в отдельной ветке.

Такой подход мотивируется тем, что во время программирования могут часто меняться приоритеты и при командной разработке требуется максимальное разграничение задач между участниками. Представь ситуацию, что ты с самого утра бьешься над реализацией новой функции, а тут телефонный звонок от пользователя, который обнаружил критичный баг и требует срочного исправления. Следуя идеологии Git, твои действия сведутся к созданию новой ветки, внесению исправлений и выполнению слияния с рабочей веткой. При этом изменения, сделанные для реализации новой функции, не попадут в основную ветку (при условии, что они также выполнялись в отдельной ветке).

Так, а что же является веткой в Git? Как они формируются и почему создание ветки не требует отдельной копии проекта, как это принято в других системах управления версиями? Чтобы ответить на эти вопросы, нам потребуется вернуться к началу и вспомнить, как Git хранит свои данные. В теоретической части статьи я говорил, что Git хранит не цепочку изменений, а слепки.

Итак, когда мы говорим о ветках применительно к Git, то на самом деле мы подразумеваем указатель. Не определенную копию проекта, а просто указатель на один из коммитов. Раз указатель ссылается на коммит, то можно сделать вывод, что эта сущность подвижна и каждое новое движение будет сопровождаться очередным коммитом. Число веток в Git не ограничено, и если следовать всем заповедям (одна ветка на задачу), то веток может быть сколько угодно, но срок их жизни будет недолгим. Рано или поздно все ветки сольются с другими или сразу с главной веткой.

Так, а что такое главная ветка? Когда ты создаешь новый репозиторий, то в нем автоматически создается одна ветка — master. Если не создавать дополнительных веток, то вся работа будет происходить в master, что является плохой практикой. Ветка master по факту представляет собой рабочую копию решения, которая может быть в кратчайшие сроки развернута на рабочем сервере.

Увы, в рамках одной статьи я не могу разжевать все нюансы и рассказать подробности работы веток, поэтому давай сразу перейдем к практике и попробуем создать отдельную ветку. Каждая новая ветка создается при помощи команды «git branch <Имя ветки>». Попробуем создать новую ветку под именем test-branch в нашем проекте. Выполняем в консоли:

$ git branch test # Создаем новую ветку «test»

Безошибочное выполнение команды будет означать, что новая ветка была создана. Правда, создание ветки не означает, что мы сразу переходим на нее и все последующие изменения будут учитываться в рамках новой ветки. Для перехода на ветку test требуется выполнить еще одну команду:

$ git checkout test-branch

Git checkout переведет нас на ветку test-branch, и мы сразу можем приступать к внесению изменений. Открой любой файл своего тестового проекта и попробуй что-нибудь в нем изменить. В своем проекте я открыл файл BaseCalculator.cs, описывающий абстрактный класс, и добавил в нем описание нового метода GetHelloWorldString(). После этого я сохранил изменения и сделал коммит:

$ git add “Abstract Classes/BaseCalculator.cs” # Подготавливаем файл
$ git commit -m “add GetHelloWorldString()” # Выполняем коммит

Изменения в test-branch зафиксированы, теперь попробуем посмотреть, что произошло в ветке master. Для переключения на другую ветку выполни уже знакомую команду checkout:

$ git checkout master

Попробуй открыть модифицированный файл и убедись, что внесенных несколькими минутами ранее изменений там нет. Они остались в ветке test-branch, и, чтобы к ним вернуться, мы должны опять выполнить переход.

Разбираемся с ветвлениями в Git

Чтобы легче освоить такую непростую вещь, как ветвление, я настоятельно рекомендую попробовать пройти интерактивное обучение при помощи веб-сервиса LearnGitBranching. Выглядит это так. Ты получаешь доступ к виртуальной консоли и ряду практических задач. В твоем распоряжении несколько команд (commit, branch, checkout, cherry-pick, reset, revert, rebase и merge) и небольшой кусок справки. С их помощью тебе и предстоит биться с предложенными квестами. Надо отметить, что сложность задач хорошо варьируется. Если сначала предлагают совсем уж пустяковые, над решением которых думать особо не требуется, то потом начинается настоящий рок-н-ролл. На таких задачах и в хелп не стыдно заглянуть.

Сливаемся в едином порыве

У нас имеется две ветки, в одной из которых (test-branch) были изменения (напомню, я добавил описание нового метода). Будем считать, что эти изменения полностью готовы для отправки в основную ветку, то есть в master. Для слияния веток применяется команда merge. Попробуем слить ветку test-branch с master:

$ git checkout master # Переходим на ветку master
$ git merge test-branch # Выполняем слияние с веткой test-branch

Выполнение этих команд будет обязательно сопровождаться сообщением «Fast forward» (на сленге говорят «переметка»). Оно подразумевает, что удача на нашей стороне и Git удалось объединить все изменения без лишнего геморроя. Успеху мы обязаны нашему коммиту, а точнее, его наследственности. Ветка test-branch сразу указывала на коммит, являющийся прямым родителем коммита, с которым мы работаем в настоящее время.

Хорошо, а что, если удача повернулась к нам задом и повторить такой финт не удается? Как Git поступит в этом случае? Такие ситуации заставляют Git попотеть: ему приходится выполнить трехходовое слияние на основе двух снимков состояния репозитория, на которые ссылаются вершины веток и общий слепок-прародитель для этих двух веток.

По окончании этих манипуляций Git создаст новый коммит, который принято называть коммит-слияния. Свое название он получил из-за того, что имеет больше одного предка. Обрати внимание, что Git и в этом случае берет всю работу по организации слияния на себя. Он проанализирует возможные варианты и остановится на лучшем предке. Если слияние выполнилось успешно (нет никаких ошибок), то можно не стесняться и удалять ненужную ветку:

$ git branch -d test-branch

На этом слияние можно считать завершенным, все изменения, сделанные в ветке test-branch, мигрировали в master.

Разбор конфликтов

Рано или поздно у тебя обязательно возникнет ситуация, когда изменения, сделанные в одной ветке, наглым образом конфликтуют с изменениями в другой. Подобные вещи появляются, если ты изменишь одну и ту же часть файла в разных ветках.

Git подобные конфликты самостоятельно разрулить не может, так что эта работа ложится на твои плечи. Если конфликт возникнет, то ответом на команду merge будет сообщение: «CONFLICT (content): Merge conflict in BaseCalculator.cs». Получить список всех проблемных файлов ты всегда можешь при помощи команды git status. В приведенном примере видно, что конфликт возник в файле BaseCalculator.cs. Если открыть этот файл сейчас, то в районе конфликтного участка будет что-то вроде:

<<<<<<< HEAD:BaseCalculator.cs
return 3;
=======
int i = 4;
return = I +2;
>>>>>>> hotfix31337:BaseCalculator.cs

В верхней части блока приведен код из ветки master, а в нижней — из hotfix31337. Реализация методов в двух ветках сильно отличается. Конфликт разрешается путем самостоятельного редактирования файла. Например, либо ты просто удаляешь вариант из ветки master и оставляешь лишь новую реализацию (int i = 4; return = I + 2;), либо собираешь из двух кусков один. Такую операцию необходимо произвести для каждого конфликта и по завершении выполнить для них git add.

GUI-тулза для сравнения исходников
GUI-тулза для сравнения исходников
Результат выполнения GitStatus
Результат выполнения GitStatus

INFO

Плагины для популярных IDE/редакторов

Вместо заключения

Переходить или нет на Git — дело личное. Да, он может показаться сложным и даже неуклюжим, но, поверь, это лишь первое впечатление. Достаточно перевести на него пару своих рабочих проектов и попробовать реально поработать с системой несколько дней. Уверен, уже через неделю консольные команды не будут так страшны, а ты перестанешь лишний раз переживать при работе с исходным кодом в команде. В общем, идею ты понял, и мне остается лишь пожелать тебе хороших коммитов и денежных проектов. Удачи!

Большая шпаргалка

Первое знакомство с Git оставляет неоднозначное впечатление: куча команд, ветки, консоль и другие непонятные вещи. Чтобы тебе сразу не запутаться во всем этом хозяйстве, я подготовил для тебя большую шпаргалку. В ней я собрал команды, которые чаще всего использую. Надеюсь, эта шпора сможет помочь тебе в трудную минуту.

  • git branch <имя ветки> — создать новую ветку;
  • git branch –list — вывести список всех созданных веток;
  • git help <Имя команды> — вывести справку по определенной команде;
  • git commit –amend — сделать последний коммит еще раз;
  • git add <Имя файла|маска> — подготовить файлы (добавить в версионный контроль);
  • git reset <Имя файла> — убрать файл из индекса;
  • git checkout <имя ветки> — переключится на ветку;
  • git status — получить текущее состояние файлов проекта;
  • git clone <Источник> — клонировать существующий репозиторий;
  • git diff — отобразить список неиндексированных изменений;
  • git diff –cached — вывести список изменений, которые войдут в следующий коммит;
  • git commit -m <комментарий> — сделать коммит (фиксацию изменений) с произвольным комментарием;
  • git fetch <url или алиас> — получить все изменения из репозитория;
  • git push <url или алиас> <ветка> — закинуть свои изменения на удаленный сервер в определенную ветку;
  • git add -u — подготовить все измененные файлы;
  • git init — создать директорию Git в текущем каталоге;
  • git diff –staged — сравнить индексированные файлы с последним коммитом;
  • git rm <Имя файла> — удалить файл из индекса;
  • git log — отобразить историю коммитов;
  • git checkout – <Имя файла> — отменить изменения, сделанные в файле;
  • git remote -v — просмотреть список соответствия алиасов и URL;
  • git remote add <алиас> — добавить сокращение для URL;
  • git tag <Имя метки> — добавить метку;
  • git merge <Имя ветки> — слияние с веткой;
  • git branch -d <Имя ветки> — удалить ветку.

Игорь «Spider_NET» Антонов, antonov.igor.khv@gmail.com, vr-online.ru


Читать дальше
Twitter
Одноклассники
Мой Мир

материал с xakep.ru

12

      Add

      You can create thematic collections and keep, for instance, all recipes in one place so you will never lose them.

      No images found
      Previous Next 0 / 0
      500
      • Advertisement
      • Animals
      • Architecture
      • Art
      • Auto
      • Aviation
      • Books
      • Cartoons
      • Celebrities
      • Children
      • Culture
      • Design
      • Economics
      • Education
      • Entertainment
      • Fashion
      • Fitness
      • Food
      • Gadgets
      • Games
      • Health
      • History
      • Hobby
      • Humor
      • Interior
      • Moto
      • Movies
      • Music
      • Nature
      • News
      • Photo
      • Pictures
      • Politics
      • Psychology
      • Science
      • Society
      • Sport
      • Technology
      • Travel
      • Video
      • Weapons
      • Web
      • Work
        Submit
        Valid formats are JPG, PNG, GIF.
        Not more than 5 Мb, please.
        30
        surfingbird.ru/site/
        RSS format guidelines
        500
        • Advertisement
        • Animals
        • Architecture
        • Art
        • Auto
        • Aviation
        • Books
        • Cartoons
        • Celebrities
        • Children
        • Culture
        • Design
        • Economics
        • Education
        • Entertainment
        • Fashion
        • Fitness
        • Food
        • Gadgets
        • Games
        • Health
        • History
        • Hobby
        • Humor
        • Interior
        • Moto
        • Movies
        • Music
        • Nature
        • News
        • Photo
        • Pictures
        • Politics
        • Psychology
        • Science
        • Society
        • Sport
        • Technology
        • Travel
        • Video
        • Weapons
        • Web
        • Work

          Submit

          Thank you! Wait for moderation.

          Тебе это не нравится?

          You can block the domain, tag, user or channel, and we'll stop recommend it to you. You can always unblock them in your settings.

          • modrarus
          • домен xakep.ru

          Get a link

          Спасибо, твоя жалоба принята.

          Log on to Surfingbird

          Recover
          Sign up

          or

          Welcome to Surfingbird.com!

          You'll find thousands of interesting pages, photos, and videos inside.
          Join!

          • Personal
            recommendations

          • Stash
            interesting and useful stuff

          • Anywhere,
            anytime

          Do we already know you? Login or restore the password.

          Close

          Add to collection

             

            Facebook

            Ваш профиль на рассмотрении, обновите страницу через несколько секунд

            Facebook

            К сожалению, вы не попадаете под условия акции