{
  "cells": [
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "# Hafta 1: Versiyon Kontrol Sistemleri ve İşbirliği Platformları (Git & GitHub)\n\n**Dersin Hedefleri:**\n1. Versiyon kontrolünün ne olduğunu ve neden veri bilimi projelerinde kritik olduğunu anlamak.\n2. Temel `git` komutlarını (`init`, `add`, `commit`, `status`, `log`, `diff`) etkin bir şekilde kullanmak.\n3. Dallanma (branching) ve birleştirme (merging) kavramlarını öğrenmek ve feature-branch iş akışını uygulamak.\n4. **Conflict çözme** yöntemlerini öğrenmek ve merge conflict'larını güvenle yönetmek.\n5. **Git Stash** ile geçici değişiklikleri yönetmeyi öğrenmek.\n6. **PyCharm IDE'si** üzerinden Git operasyonlarını görsel arayüzle gerçekleştirmek.\n7. GitHub platformunu kullanarak repository oluşturmak, fork etmek, pull request açmak ve kod incelemesi yapmak.\n8. Veri bilimi projelerine özgü `.gitignore` dosyası yapılandırması yapmak.\n9. Takım çalışması için gerekli Git iş akışlarını ve en iyi uygulamaları kavramak."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 1. Versiyon Kontrol Nedir ve Neden Önemlidir?\n\nVersiyon kontrol, dosyalarınızda zaman içinde yapılan değişiklikleri takip eden, geçmişe dönmeyi ve farklı sürümleri karşılaştırmayı sağlayan bir sistemdir. Veri bilimi projelerinde versiyon kontrolün kritik önemleri:\n\n### Veri Bilimi İçin Özel Faydalar:\n- **Deney Takibi:** Farklı hiperparametreleri, özellik kombinasyonlarını ve modelleri paralel dallar halinde deneyebilirsiniz.\n- **Veri Lineage:** Hangi veri ön işleme adımının hangi sonucu verdiğini takip edebilirsiniz.\n- **Model Versiyonlama:** Farklı model sürümlerini karşılaştırabilir ve en iyi performansı verenine geri dönebilirsiniz.\n- **Notebook Yönetimi:** Jupyter notebook'larının karmaşık durumlarını (output'lar dahil) etkili şekilde yönetebilirsiniz.\n- **Takım İşbirliği:** Veri bilimciler, mühendisler ve domain uzmanları aynı proje üzerinde senkronize şekilde çalışabilir.\n\n**Git**, günümüzde en yaygın kullanılan **dağıtık** versiyon kontrol sistemidir. Her geliştirici, projenin tam geçmişine sahip olur."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 2. Git'in Temel Kavramları ve İş Akışı\n\n### 2.1. Temel Kavramlar\n- **Repository (Depo):** Projenizin ve geçmişinin saklandığı klasör (`.git` klasörü içerir).\n- **Working Directory (Çalışma Dizini):** Dosyalarınızı düzenlediğiniz alan.\n- **Staging Area (Index/Hazırlama Alanı):** Commit'e hazır olan değişikliklerin bekletildiği ara alan.\n- **Commit:** Projenizin belirli bir andaki anlık görüntüsü. SHA hash ile benzersiz kimliği vardır.\n- **Branch (Dal):** Projenin paralel bir geliştirme hattı. Bağımsız özellik geliştirme için kullanılır.\n- **HEAD:** Şu anda çalıştığınız commit'i gösteren pointer.\n- **Origin:** Varsayılan uzak repository (remote) adı.\n\n### 2.2. Git İş Akışı (Git Workflow)\n```\nWorking Directory -> Staging Area -> Local Repository -> Remote Repository\n     (git add)        (git commit)      (git push)\n```"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 3. Pratik Uygulama: Kapsamlı Git Projesi\n\nBu bölümde, gerçek bir veri bilimi projesi simüle ederek Git'in tüm özelliklerini deneyimleyeceğiz."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "import os\nimport subprocess\nimport pandas as pd\nimport numpy as np\nimport shutil\nimport time\n\n# Örnek proje için çalışma dizini oluşturalım\nproject_name = \"makine_ogrenmesi_projesi\"\nif os.path.exists(project_name):\n    shutil.rmtree(project_name)\n\nos.makedirs(project_name)\noriginal_dir = os.getcwd()\nos.chdir(project_name)\n\nprint(f\"Çalışma dizini: {os.getcwd()}\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 3.1. Gelişmiş Git Komut Fonksiyonu"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "def run_git_command(command, description=\"\", show_output=True, check_error=True):\n    \"\"\"Geliştirilmiş Git komut çalıştırıcı.\"\"\"\n    if show_output:\n        print(f\"\\n--- {description} ---\")\n        print(f\"Komut: git {command}\")\n\n    result = subprocess.run(\n        [\"git\"] + command.split(),\n        capture_output=True,\n        text=True,\n        cwd=os.getcwd()\n    )\n\n    if show_output:\n        if result.stdout:\n            print(\"Çıktı:\", result.stdout.strip())\n        if result.stderr and check_error:\n            print(\"Hata/Uyarı:\", result.stderr.strip())\n\n    return result.returncode == 0, result.stdout, result.stderr\n\ndef git_status():\n    \"\"\"Kısa git status komutu.\"\"\"\n    success, stdout, stderr = run_git_command(\"status --porcelain\", \"\", False)\n    return stdout.strip().split('\\n') if stdout.strip() else []\n\n# Repository başlatma ve temel yapılandırma\nrun_git_command(\"init\", \"Git repository'si başlatılıyor\")\nrun_git_command(\"config user.name 'Veri Bilimci'\", \"Kullanıcı adı ayarlanıyor\")\nrun_git_command(\"config user.email 'veri@example.com'\", \"E-posta ayarlanıyor\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 3.2. Proje Yapısını Oluşturma"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# Kapsamlı proje yapısı oluşturma\ndef create_project_structure():\n    \"\"\"Gerçekçi bir ML projesi yapısı oluşturur.\"\"\"\n\n    # Klasör yapısı\n    folders = [\n        \"data/raw\",\n        \"data/processed\",\n        \"data/external\",\n        \"notebooks/exploratory\",\n        \"notebooks/modeling\",\n        \"src/data\",\n        \"src/features\",\n        \"src/models\",\n        \"src/visualization\",\n        \"tests\",\n        \"models\",\n        \"reports/figures\",\n        \"configs\"\n    ]\n\n    for folder in folders:\n        os.makedirs(folder, exist_ok=True)\n        # Python paketleri için __init__.py\n        if 'src/' in folder:\n            open(os.path.join(folder, \"__init__.py\"), 'w').close()\n\n# README.md - Kapsamlı proje dokümantasyonu\nreadme_content = \"\"\"# Makine Öğrenmesi Projesi\n\nBu proje, müşteri churn tahmini için end-to-end bir makine öğrenmesi pipeline'ı içerir.\n\n## Proje Yapısı\n\n```\n├── data/\n│   ├── raw/                 # Ham veri dosyaları\n│   ├── processed/           # İşlenmiş veri\n│   └── external/            # Harici veri kaynakları\n├── notebooks/\n│   ├── exploratory/         # Keşifsel veri analizi\n│   └── modeling/            # Model geliştirme\n├── src/\n│   ├── data/                # Veri işleme modülleri\n│   ├── features/            # Özellik mühendisliği\n│   ├── models/              # Model eğitimi ve değerlendirme\n│   └── visualization/       # Görselleştirme araçları\n├── tests/                   # Unit testler\n├── models/                  # Eğitilmiş model dosyaları\n├── reports/                 # Analiz raporları\n└── configs/                 # Yapılandırma dosyaları\n```\n\n## Kurulum\n\n```bash\npip install -r requirements.txt\n```\n\n## Kullanım\n\n1. Veri hazırlama: `python src/data/make_dataset.py`\n2. Özellik mühendisliği: `python src/features/build_features.py`\n3. Model eğitimi: `python src/models/train_model.py`\n\n## Katkıda Bulunma\n\n1. Fork edin\n2. Feature branch oluşturun (`git checkout -b feature/yeni-ozellik`)\n3. Değişikliklerinizi commit edin\n4. Branch'ınızı push edin\n5. Pull Request açın\n\n## Lisans\n\nMIT License\n\"\"\"\n\n# Temel dosyaları oluştur\ncreate_project_structure()\n\nwith open(\"README.md\", \"w\", encoding=\"utf-8\") as f:\n    f.write(readme_content)\n\n# requirements.txt\nrequirements = \"\"\"pandas>=1.3.0\nnumpy>=1.21.0\nscikit-learn>=1.0.0\nmatplotlib>=3.5.0\nseaborn>=0.11.0\njupyter>=1.0.0\npytest>=6.0.0\n\"\"\"\n\nwith open(\"requirements.txt\", \"w\") as f:\n    f.write(requirements)\n\nprint(\"Proje yapısı oluşturuldu.\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 3.3. Kaynak Kod Modülleri Oluşturma"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# src/data/make_dataset.py - Veri yükleme modülü\ndata_module = \"\"\"\nimport pandas as pd\nimport numpy as np\nfrom pathlib import Path\n\ndef load_raw_data(file_path):\n    \\\"\\\"\\\"Ham veriyi yükler ve temel temizlik yapar.\\\"\\\"\\\"\n    try:\n        df = pd.read_csv(file_path)\n        print(f\"Veri yüklendi: {df.shape[0]} satır, {df.shape[1]} sütun\")\n        return df\n    except FileNotFoundError:\n        print(f\"Hata: {file_path} dosyası bulunamadı\")\n        return None\n\ndef basic_data_validation(df):\n    \\\"\\\"\\\"Temel veri doğrulama kontrolleri.\\\"\\\"\\\"\n    validation_results = {\n        'null_counts': df.isnull().sum(),\n        'data_types': df.dtypes,\n        'duplicate_rows': df.duplicated().sum()\n    }\n    return validation_results\n\ndef save_processed_data(df, output_path):\n    \\\"\\\"\\\"İşlenmiş veriyi kaydeder.\\\"\\\"\\\"\n    df.to_csv(output_path, index=False)\n    print(f\"İşlenmiş veri kaydedildi: {output_path}\")\n\nif __name__ == \"__main__\":\n    # Örnek kullanım\n    print(\"Veri yükleme modülü çalıştırılıyor...\")\n\"\"\"\n\nwith open(\"src/data/make_dataset.py\", \"w\", encoding=\"utf-8\") as f:\n    f.write(data_module)\n\n# src/features/build_features.py - Özellik mühendisliği\nfeatures_module = \"\"\"\nimport pandas as pd\nimport numpy as np\nfrom sklearn.preprocessing import StandardScaler, LabelEncoder\n\ndef create_age_groups(df, age_column='age'):\n    \\\"\\\"\\\"Yaş grupları oluşturur.\\\"\\\"\\\"\n    df = df.copy()\n    df['age_group'] = pd.cut(df[age_column],\n                            bins=[0, 25, 35, 50, 100],\n                            labels=['young', 'adult', 'middle', 'senior'])\n    return df\n\ndef encode_categorical_features(df, categorical_columns):\n    \\\"\\\"\\\"Kategorik özellikleri kodlar.\\\"\\\"\\\"\n    df = df.copy()\n    encoders = {}\n\n    for col in categorical_columns:\n        if col in df.columns:\n            le = LabelEncoder()\n            df[col] = le.fit_transform(df[col].astype(str))\n            encoders[col] = le\n\n    return df, encoders\n\ndef scale_numerical_features(df, numerical_columns):\n    \\\"\\\"\\\"Sayısal özellikleri ölçeklendirir.\\\"\\\"\\\"\n    df = df.copy()\n    scaler = StandardScaler()\n\n    df[numerical_columns] = scaler.fit_transform(df[numerical_columns])\n\n    return df, scaler\n\nif __name__ == \"__main__\":\n    print(\"Özellik mühendisliği modülü çalıştırılıyor...\")\n\"\"\"\n\nwith open(\"src/features/build_features.py\", \"w\", encoding=\"utf-8\") as f:\n    f.write(features_module)\n\n# Örnek veri dosyası\nnp.random.seed(42)\nsample_data = pd.DataFrame({\n    'customer_id': range(1, 1001),\n    'age': np.random.randint(18, 80, 1000),\n    'income': np.random.normal(50000, 15000, 1000),\n    'tenure': np.random.randint(1, 120, 1000),\n    'city': np.random.choice(['Istanbul', 'Ankara', 'Izmir', 'Bursa'], 1000),\n    'churn': np.random.choice([0, 1], 1000, p=[0.7, 0.3])\n})\n\nsample_data.to_csv(\"data/raw/customer_data.csv\", index=False)\nprint(\"Örnek veri dosyası oluşturuldu.\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 3.4. İlk Commit ve Geçmiş Takibi"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# .gitignore dosyası - Veri bilimi projeleri için kapsamlı\ngitignore_content = \"\"\"# Veri bilimi projesi için .gitignore\n\n# Büyük veri dosyaları\n*.csv\n!data/raw/customer_data.csv  # Örnek veri dosyası hariç\n*.parquet\n*.hdf5\n*.xlsx\n*.h5\n*.db\n*.sqlite\n\n# Model dosyaları\n*.pkl\n*.joblib\n*.model\n*.h5\n*.pb\nmodels/*.pkl\nmodels/*.joblib\n\n# Jupyter Notebook\n.ipynb_checkpoints/\n*/.ipynb_checkpoints/*\n*.ipynb_checkpoints\n\n# Python\n__pycache__/\n*.py[cod]\n*$py.class\n*.so\n.Python\nbuild/\ndevelop-eggs/\ndist/\ndownloads/\neggs/\n.eggs/\nlib/\nlib64/\nparts/\nsdist/\nvar/\nwheels/\n*.egg-info/\n.installed.cfg\n*.egg\n\n# Virtual environments\nvenv/\nenv/\nENV/\n.venv/\n.conda/\n\n# IDE files\n.vscode/\n.idea/\n*.swp\n*.swo\n*~\n\n# OS files\n.DS_Store\n.DS_Store?\n._*\n.Spotlight-V100\n.Trashes\nehthumbs.db\nThumbs.db\n\n# Environment variables\n.env\n.env.local\n.env.production\n\n# Logs\n*.log\nlogs/\n\n# Cache\n.cache/\n.pytest_cache/\n\n# Temporary files\n*.tmp\n*.temp\ntmp/\n\n# MLflow\nmlruns/\nmlartifacts/\n\n# DVC\n.dvc/\n*.dvc\n\n# Airflow\nairflow.db\nairflow-webserver.pid\n\"\"\"\n\nwith open(\".gitignore\", \"w\", encoding=\"utf-8\") as f:\n    f.write(gitignore_content)\n\n# İlk commit\nrun_git_command(\"add .\", \"Tüm dosyalar staging area'ya ekleniyor\")\nrun_git_command('commit -m \"İlk commit: Proje yapısı ve temel modüller eklendi\\n\\n- Kapsamlı klasör yapısı oluşturuldu\\n- Veri işleme ve özellik mühendisliği modülleri eklendi\\n- .gitignore dosyası yapılandırıldı\\n- Örnek veri dosyası eklendi\"',\n                \"İlk commit yapılıyor\")\n\nrun_git_command(\"log --oneline\", \"Commit geçmişi\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 4. Branching Stratejileri ve Gelişmiş İş Akışları\n\n### 4.1. Feature Branch İş Akışı\n\nProfesyonel projelerde her yeni özellik için ayrı dal oluşturmak standart uygulamadır."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# Mevcut dalları ve durumu görme\nrun_git_command(\"branch -v\", \"Mevcut dallar ve son commit'ler\")\nrun_git_command(\"status\", \"Çalışma dizini durumu\")\n\n# Feature branch oluşturma - Model geliştirme\nrun_git_command(\"checkout -b feature/model-development\",\n                \"Model geliştirme dalı oluşturuluyor\")\n\n# Model eğitimi modülü\nmodel_module = \"\"\"\nimport pandas as pd\nimport numpy as np\nfrom sklearn.model_selection import train_test_split\nfrom sklearn.ensemble import RandomForestClassifier\nfrom sklearn.linear_model import LogisticRegression\nfrom sklearn.metrics import accuracy_score, classification_report, confusion_matrix\nimport joblib\nfrom datetime import datetime\n\nclass ChurnPredictor:\n    \\\"\\\"\\\"Müşteri churn tahmini için model sınıfı.\\\"\\\"\\\"\n\n    def __init__(self, model_type='random_forest'):\n        self.model_type = model_type\n        self.model = None\n        self.is_trained = False\n\n    def get_model(self):\n        \\\"\\\"\\\"Model tipine göre model döndürür.\\\"\\\"\\\"\n        if self.model_type == 'random_forest':\n            return RandomForestClassifier(n_estimators=100, random_state=42)\n        elif self.model_type == 'logistic':\n            return LogisticRegression(random_state=42)\n        else:\n            raise ValueError(f\"Desteklenmeyen model tipi: {self.model_type}\")\n\n    def train(self, X_train, y_train):\n        \\\"\\\"\\\"Modeli eğitir.\\\"\\\"\\\"\n        self.model = self.get_model()\n        self.model.fit(X_train, y_train)\n        self.is_trained = True\n        print(f\"{self.model_type} modeli eğitildi.\")\n\n    def predict(self, X_test):\n        \\\"\\\"\\\"Tahmin yapar.\\\"\\\"\\\"\n        if not self.is_trained:\n            raise ValueError(\"Model henüz eğitilmemiş!\")\n        return self.model.predict(X_test)\n\n    def evaluate(self, X_test, y_test):\n        \\\"\\\"\\\"Model performansını değerlendirir.\\\"\\\"\\\"\n        predictions = self.predict(X_test)\n        accuracy = accuracy_score(y_test, predictions)\n        report = classification_report(y_test, predictions)\n\n        return {\n            'accuracy': accuracy,\n            'classification_report': report,\n            'predictions': predictions\n        }\n\n    def save_model(self, filepath):\n        \\\"\\\"\\\"Modeli kaydeder.\\\"\\\"\\\"\n        if not self.is_trained:\n            raise ValueError(\"Eğitilmemiş model kaydedilemez!\")\n\n        model_data = {\n            'model': self.model,\n            'model_type': self.model_type,\n            'training_date': datetime.now().isoformat()\n        }\n\n        joblib.dump(model_data, filepath)\n        print(f\"Model kaydedildi: {filepath}\")\n\nif __name__ == \"__main__\":\n    print(\"Churn tahmin modeli modülü hazır.\")\n\"\"\"\n\nwith open(\"src/models/train_model.py\", \"w\", encoding=\"utf-8\") as f:\n    f.write(model_module)\n\n# Model geliştirme dalındaki değişiklikleri commit etme\nrun_git_command(\"add .\", \"Model modülü ekleniyor\")\nrun_git_command('commit -m \"Model eğitimi modülü eklendi\\n\\n- ChurnPredictor sınıfı oluşturuldu\\n- Random Forest ve Logistic Regression desteği\\n- Model değerlendirme ve kaydetme fonksiyonları\"',\n                \"Model modülü commit'i\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 5. Git Stash: Geçici Değişiklikleri Yönetme\n\nGit Stash, henüz commit etmeye hazır olmayan değişiklikleri geçici olarak saklamanıza olanak tanır."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# Stash senaryosu: Yarım kalmış bir özellik üzerinde çalışıyoruz\nprint(\"\\n=== GIT STASH SENARYOSU ===\")\n\n# Visualization modülü üzerinde çalışmaya başlıyoruz\nviz_module_incomplete = \"\"\"\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport pandas as pd\n\ndef plot_age_distribution(df):\n    \\\"\\\"\\\"Yaş dağılımını çizer.\\\"\\\"\\\"\n    plt.figure(figsize=(10, 6))\n    plt.hist(df['age'], bins=30, alpha=0.7)\n    plt.title('Müşteri Yaş Dağılımı')\n    plt.xlabel('Yaş')\n    plt.ylabel('Frekans')\n    # TODO: Daha fazla stil ayarı eklenecek\n    # TODO: Outlier analizi eklenecek\n\"\"\"\n\nwith open(\"src/visualization/plots.py\", \"w\", encoding=\"utf-8\") as f:\n    f.write(viz_module_incomplete)\n\nrun_git_command(\"add src/visualization/plots.py\", \"Yarım kalmış dosya ekleniyor\")\nrun_git_command(\"status\", \"Yarım kalmış çalışma durumu\")\n\n# Acil bir düzeltme için ana dala geçmemiz gerekiyor\n# Ama yarım kalmış işimizi kaybetmek istemiyoruz\nprint(\"\\n--- Acil düzeltme gerekli! Yarım kalmış işi stash'liyoruz ---\")\n\nrun_git_command(\"stash push -m 'Görselleştirme modülü yarım kalmış - TODO listesi var'\",\n                \"Değişiklikler stash'leniyor\")\n\nrun_git_command(\"status\", \"Stash sonrası temiz çalışma dizini\")\nrun_git_command(\"stash list\", \"Stash listesi\")\n\n# Ana dala geçiş yapabiliriz\nrun_git_command(\"checkout main\", \"Ana dala geçiş\")\n\n# Acil düzeltme: README'de bir typo\nwith open(\"README.md\", \"r\", encoding=\"utf-8\") as f:\n    content = f.read()\n\n# Basit bir düzeltme\ncontent = content.replace(\"Katkıda Bulunma\", \"Katkıda Bulunma\")  # Aslında değişiklik yok, demo için\ncontent = content.replace(\"MIT License\", \"MIT License\\n\\n## Versiyon\\n\\nv1.0.0\")\n\nwith open(\"README.md\", \"w\", encoding=\"utf-8\") as f:\n    f.write(content)\n\nrun_git_command(\"add README.md\", \"README düzeltmesi\")\nrun_git_command('commit -m \"Hotfix: README.md güncellemesi - versiyon bilgisi eklendi\"',\n                \"Acil düzeltme commit'i\")\n\n# Şimdi feature branch'e geri dönüp stash'lenmiş işimizi geri alabiliriz\nrun_git_command(\"checkout feature/model-development\", \"Feature dalına geri dönüş\")\n\n# Stash'lenmiş değişiklikleri geri alma\nrun_git_command(\"stash pop\", \"Stash'lenmiş değişiklikler geri alınıyor\")\nrun_git_command(\"status\", \"Stash pop sonrası durum\")\n\n# Şimdi görselleştirme modülünü tamamlayabiliriz\nviz_module_complete = \"\"\"\nimport matplotlib.pyplot as plt\nimport seaborn as sns\nimport pandas as pd\nimport numpy as np\n\ndef plot_age_distribution(df, save_path=None):\n    \\\"\\\"\\\"Yaş dağılımını çizer.\\\"\\\"\\\"\n    plt.figure(figsize=(12, 8))\n\n    # Histogram\n    plt.subplot(2, 2, 1)\n    plt.hist(df['age'], bins=30, alpha=0.7, color='skyblue', edgecolor='black')\n    plt.title('Müşteri Yaş Dağılımı')\n    plt.xlabel('Yaş')\n    plt.ylabel('Frekans')\n    plt.grid(True, alpha=0.3)\n\n    # Box plot\n    plt.subplot(2, 2, 2)\n    plt.boxplot(df['age'])\n    plt.title('Yaş Dağılımı - Box Plot')\n    plt.ylabel('Yaş')\n\n    # Churn'e göre yaş dağılımı\n    plt.subplot(2, 2, 3)\n    if 'churn' in df.columns:\n        for churn_val in df['churn'].unique():\n            subset = df[df['churn'] == churn_val]['age']\n            plt.hist(subset, alpha=0.7, label=f'Churn: {churn_val}', bins=20)\n        plt.legend()\n        plt.title('Churn Durumuna Göre Yaş Dağılımı')\n        plt.xlabel('Yaş')\n        plt.ylabel('Frekans')\n\n    # İstatistikler\n    plt.subplot(2, 2, 4)\n    stats_text = f\"\"\"İstatistikler:\n    Ortalama: {df['age'].mean():.1f}\n    Medyan: {df['age'].median():.1f}\n    Std. Sapma: {df['age'].std():.1f}\n    Min: {df['age'].min()}\n    Max: {df['age'].max()}\"\"\"\n    plt.text(0.1, 0.5, stats_text, fontsize=12, verticalalignment='center')\n    plt.axis('off')\n\n    plt.tight_layout()\n\n    if save_path:\n        plt.savefig(save_path, dpi=300, bbox_inches='tight')\n        print(f\"Grafik kaydedildi: {save_path}\")\n\n    plt.show()\n\ndef plot_correlation_matrix(df, save_path=None):\n    \\\"\\\"\\\"Korelasyon matrisini çizer.\\\"\\\"\\\"\n    numerical_cols = df.select_dtypes(include=[np.number]).columns\n    correlation_matrix = df[numerical_cols].corr()\n\n    plt.figure(figsize=(10, 8))\n    sns.heatmap(correlation_matrix, annot=True, cmap='coolwarm', center=0,\n                square=True, linewidths=0.5)\n    plt.title('Özellikler Arası Korelasyon Matrisi')\n    plt.tight_layout()\n\n    if save_path:\n        plt.savefig(save_path, dpi=300, bbox_inches='tight')\n        print(f\"Korelasyon matrisi kaydedildi: {save_path}\")\n\n    plt.show()\n\ndef plot_churn_analysis(df, save_path=None):\n    \\\"\\\"\\\"Churn analizini görselleştirir.\\\"\\\"\\\"\n    if 'churn' not in df.columns:\n        print(\"Churn sütunu bulunamadı!\")\n        return\n\n    fig, axes = plt.subplots(2, 2, figsize=(15, 12))\n\n    # Churn oranı\n    churn_counts = df['churn'].value_counts()\n    axes[0, 0].pie(churn_counts.values, labels=['Kalan', 'Ayrılan'],\n                   autopct='%1.1f%%', startangle=90)\n    axes[0, 0].set_title('Churn Oranı')\n\n    # Yaşa göre churn\n    axes[0, 1].boxplot([df[df['churn']==0]['age'], df[df['churn']==1]['age']])\n    axes[0, 1].set_xticklabels(['Kalan', 'Ayrılan'])\n    axes[0, 1].set_title('Yaşa Göre Churn')\n    axes[0, 1].set_ylabel('Yaş')\n\n    # Gelire göre churn\n    if 'income' in df.columns:\n        axes[1, 0].boxplot([df[df['churn']==0]['income'], df[df['churn']==1]['income']])\n        axes[1, 0].set_xticklabels(['Kalan', 'Ayrılan'])\n        axes[1, 0].set_title('Gelire Göre Churn')\n        axes[1, 0].set_ylabel('Gelir')\n\n    # Şehire göre churn\n    if 'city' in df.columns:\n        city_churn = df.groupby('city')['churn'].mean()\n        axes[1, 1].bar(city_churn.index, city_churn.values)\n        axes[1, 1].set_title('Şehre Göre Churn Oranı')\n        axes[1, 1].set_ylabel('Churn Oranı')\n        axes[1, 1].tick_params(axis='x', rotation=45)\n\n    plt.tight_layout()\n\n    if save_path:\n        plt.savefig(save_path, dpi=300, bbox_inches='tight')\n        print(f\"Churn analizi kaydedildi: {save_path}\")\n\n    plt.show()\n\nif __name__ == \"__main__\":\n    print(\"Görselleştirme modülü hazır.\")\n\n    # Test\n    try:\n        test_df = pd.read_csv(\"data/raw/customer_data.csv\")\n        plot_age_distribution(test_df)\n    except FileNotFoundError:\n        print(\"Test verisi bulunamadı.\")\n\"\"\"\n\nwith open(\"src/visualization/plots.py\", \"w\", encoding=\"utf-8\") as f:\n    f.write(viz_module_complete)\n\nrun_git_command(\"add .\", \"Görselleştirme modülü tamamlandı\")\nrun_git_command('commit -m \"Görselleştirme modülü tamamlandı\\n\\n- Yaş dağılımı ve churn analiz grafikleri\\n- Korelasyon matrisi görselleştirmesi\\n- Grafik kaydetme fonksiyonalitesi\\n- Test kodu eklendi\"',\n                \"Görselleştirme modülü commit'i\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 6. Merge Conflicts: Çakışma Çözme\n\nGerçek projelerde en sık karşılaşılan durumlardan biri merge conflict'lardır.\nBu durumu simüle edelim ve çözme yöntemlerini öğrenelim."
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "print(\"\\n=== MERGE CONFLICT SENARYOSU ===\")\n\n# Ana dalda da görselleştirme üzerinde çalışan başka bir geliştirici olduğunu simüle edelim\nrun_git_command(\"checkout main\", \"Ana dala geçiş\")\n\n# Ana dalda basit bir görselleştirme modülü oluşturalım (conflict için)\nsimple_viz_module = \"\"\"\nimport matplotlib.pyplot as plt\n\ndef simple_plot(df):\n    \\\"\\\"\\\"Basit bir grafik çizer.\\\"\\\"\\\"\n    plt.figure(figsize=(8, 6))\n    plt.hist(df['age'], bins=20)\n    plt.title('Yaş Dağılımı - Basit Versiyon')\n    plt.show()\n\ndef basic_statistics(df):\n    \\\"\\\"\\\"Temel istatistikleri gösterir.\\\"\\\"\\\"\n    print(f\"Ortalama yaş: {df['age'].mean():.2f}\")\n    print(f\"Minimum yaş: {df['age'].min()}\")\n    print(f\"Maksimum yaş: {df['age'].max()}\")\n\nif __name__ == \"__main__\":\n    print(\"Basit görselleştirme modülü\")\n\"\"\"\n\n# Aynı dosyayı ana dalda da oluşturalım\nwith open(\"src/visualization/plots.py\", \"w\", encoding=\"utf-8\") as f:\n    f.write(simple_viz_module)\n\nrun_git_command(\"add .\", \"Ana dalda basit görselleştirme ekleniyor\")\nrun_git_command('commit -m \"Ana dalda basit görselleştirme modülü eklendi\"',\n                \"Ana dalda görselleştirme commit'i\")\n\n# Şimdi feature branch'i merge etmeye çalışalım - conflict çıkacak!\nprint(\"\\n--- Merge conflict oluşturmaya çalışıyoruz ---\")\nsuccess, stdout, stderr = run_git_command(\"merge feature/model-development\",\n                                         \"Feature dalını merge etmeye çalışıyor\",\n                                         check_error=False)\n\nif not success:\n    print(\"Beklenen conflict oluştu!\")\n    run_git_command(\"status\", \"Conflict durumu\")\n\n    # Conflict olan dosyayı inceleyelim\n    print(\"\\n--- Conflict olan dosya içeriği ---\")\n    try:\n        with open(\"src/visualization/plots.py\", \"r\", encoding=\"utf-8\") as f:\n            conflict_content = f.read()\n        print(conflict_content[:500] + \"...\" if len(conflict_content) > 500 else conflict_content)\n    except:\n        print(\"Conflict dosyası okunamadı\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 6.1. Conflict Çözme Stratejileri\n\nGit conflict marker'ları:\n- `<<<<<<< HEAD`: Mevcut dalın değişiklikleri başlangıcı\n- `=======`: Değişikliklerin ayrımı\n- `>>>>>>> branch-name`: Merge edilen dalın değişiklikleri sonu\n\n**Çözme Yöntemleri:**\n1. **Manuel çözme**: Dosyayı editörde açıp marker'ları temizleme\n2. **Tool kullanma**: `git mergetool` komutu\n3. **Bir tarafı seçme**: `git checkout --theirs/--ours filename`"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# Conflict'i çözelim - feature branch'deki gelişmiş versiyonu alalım\nprint(\"\\n--- Conflict çözülüyor ---\")\n\n# Feature branch'deki versiyonu seçiyoruz (daha kapsamlı olduğu için)\nrun_git_command(\"checkout --theirs src/visualization/plots.py\",\n                \"Feature branch'deki versiyon seçiliyor\")\n\n# Conflict çözüldükten sonra commit etmeliyiz\nrun_git_command(\"add src/visualization/plots.py\", \"Çözülmüş dosya ekleniyor\")\nrun_git_command('commit -m \"Merge conflict çözüldü: Gelişmiş görselleştirme modülü korundu\"',\n                \"Conflict çözüm commit'i\")\n\nrun_git_command(\"log --oneline --graph\", \"Merge sonrası commit geçmişi\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 7. PyCharm ile Git Operasyonları\n\nPyCharm IDE'si, Git operasyonları için güçlü görsel araçlar sunar.\nBu bölümde PyCharm'daki temel Git işlemlerini öğreneceğiz."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 7.1. PyCharm Git Menüsü ve Kısayollar\n\n**Ana Git İşlemleri:**\n\n1. **VCS Menüsü:**\n   - `VCS → Git → Clone...` - Repository klonlama\n   - `VCS → Git → Branches...` - Dal yönetimi (Ctrl+Shift+`)\n   - `VCS → Git → Merge...` - Dal birleştirme\n   - `VCS → Git → Stash Changes...` - Değişiklikleri saklama\n\n2. **Commit İşlemleri:**\n   - `Ctrl+K` - Commit penceresi\n   - `Ctrl+Shift+K` - Push to remote\n   - `Ctrl+T` - Update project (pull)\n\n3. **Dosya Düzeyinde İşlemler:**\n   - `Ctrl+Alt+Z` - Rollback (dosyayı geri al)\n   - `Ctrl+D` - Compare with branch/tag\n   - `Alt+Shift+C` - View recent changes\n\n**PyCharm Git Özellikleri:**\n\n| Özellik | Açıklama | Kısayol |\n|---------|----------|---------|\n| **Git Log** | Commit geçmişini görsel olarak gösterir | Alt+9 |\n| **Changes View** | Değişen dosyaları listeler | Alt+9 |\n| **Diff Viewer** | Dosya değişikliklerini yan yana gösterir | Ctrl+D |\n| **Blame/Annotate** | Her satırın kim tarafından yazıldığını gösterir | Sağ tık → Git → Annotate |\n| **Shelf** | Git stash'e alternatif, PyCharm'a özel | VCS → Shelf |"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 7.2. PyCharm'da Branch Management\n\n**PyCharm Branch İşlemleri:**\n\n1. **Yeni Branch Oluşturma:**\n   - Sağ alt köşedeki branch adına tıklayın\n   - \"+ New Branch\" seçin\n   - Branch adını girin\n\n2. **Branch Değiştirme:**\n   - Branch popup'ında (Ctrl+Shift+`) istenen branch'e çift tıklayın\n   - Veya \"Checkout\" butonunu kullanın\n\n3. **Branch Silme:**\n   - Branch listesinde branch'e sağ tıklayın\n   - \"Delete\" seçin\n\n4. **Branch Karşılaştırma:**\n   - İki branch'i seçin\n   - \"Compare\" tıklayın\n   - Dosya farklarını görüntüleyin"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 7.3. PyCharm Commit İş Akışı\n\n**Commit Penceresi Özellikleri:**\n\n1. **Changed Files Panel:**\n   - Değişen dosyalar listesi\n   - Her dosya için diff gösterimi\n   - Seçici commit (bazı dosyaları commit'e dahil etmeme)\n\n2. **Commit Message:**\n   - Commit mesajı editörü\n   - Spell check\n   - Commit message templates\n\n3. **Before Commit Checks:**\n   - Code analysis (code inspection)\n   - Reformat code\n   - Optimize imports\n   - Perform code analysis\n\n4. **Commit Options:**\n   - Amend commit (son commit'i değiştir)\n   - Sign-off commit\n   - Custom commit commands"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 7.4. PyCharm Merge ve Conflict Resolution\n\n**PyCharm Merge Tool Özellikleri:**\n\n1. **Three-way Merge View:**\n   - Sol panel: Your changes (local)\n   - Orta panel: Result (merge sonucu)\n   - Sağ panel: Their changes (remote)\n\n2. **Conflict Resolution Actions:**\n   - Accept yours (yeşil ok) - Kendi değişikliğinizi kabul edin\n   - Accept theirs (mavi ok) - Diğer tarafın değişikliğini kabul edin\n   - Accept both - Her iki değişikliği de kabul edin\n   - Manual edit - Manuel olarak düzenleyin\n\n3. **Navigation:**\n   - F7: Next conflict\n   - Shift+F7: Previous conflict\n   - Ctrl+Shift+Z: Revert conflict resolution\n\n**PyCharm'da Merge Conflict Çözme Adımları:**\n1. Conflict oluştuğunda PyCharm otomatik olarak merge tool'u açar\n2. Her conflict için uygun action'ı seçin\n3. \"Apply\" butonuna tıklayın\n4. Tüm conflict'lar çözüldükten sonra merge commit'ini yapın"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 8. GitHub İş Akışları ve Best Practices\n\n### 8.1. Repository Yönetimi"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# GitHub için örnek workflow dosyası oluşturalım\ngithub_dir = \".github/workflows\"\nos.makedirs(github_dir, exist_ok=True)\n\nci_workflow = \"\"\"name: CI/CD Pipeline\n\non:\n  push:\n    branches: [ main, develop ]\n  pull_request:\n    branches: [ main ]\n\njobs:\n  test:\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        python-version: [3.8, 3.9, '3.10']\n\n    steps:\n    - uses: actions/checkout@v3\n\n    - name: Set up Python ${{ matrix.python-version }}\n      uses: actions/setup-python@v3\n      with:\n        python-version: ${{ matrix.python-version }}\n\n    - name: Install dependencies\n      run: |\n        python -m pip install --upgrade pip\n        pip install -r requirements.txt\n        pip install pytest pytest-cov\n\n    - name: Run tests\n      run: |\n        pytest tests/ --cov=src --cov-report=xml\n\n    - name: Upload coverage to Codecov\n      uses: codecov/codecov-action@v3\n      with:\n        file: ./coverage.xml\n\n  lint:\n    runs-on: ubuntu-latest\n\n    steps:\n    - uses: actions/checkout@v3\n\n    - name: Set up Python\n      uses: actions/setup-python@v3\n      with:\n        python-version: '3.9'\n\n    - name: Install linting tools\n      run: |\n        python -m pip install --upgrade pip\n        pip install flake8 black isort\n\n    - name: Run flake8\n      run: flake8 src/ tests/\n\n    - name: Check code formatting with black\n      run: black --check src/ tests/\n\n    - name: Check import sorting with isort\n      run: isort --check-only src/ tests/\n\"\"\"\n\nwith open(f\"{github_dir}/ci.yml\", \"w\", encoding=\"utf-8\") as f:\n    f.write(ci_workflow)\n\n# Pull request template\npr_template_dir = \".github\"\npr_template = \"\"\"## Açıklama\nBu PR'ın amacını ve yaptığı değişiklikleri kısaca açıklayın.\n\n## Değişiklik Türü\n- [ ] Bug fix (kırılgan olmayan değişiklik - mevcut sorunu çözer)\n- [ ] New feature (kırılgan olmayan değişiklik - yeni fonksiyonalite ekler)\n- [ ] Breaking change (mevcut fonksiyonaliteyi etkileyen değişiklik)\n- [ ] Documentation update (dokümantasyon güncellemesi)\n\n## Test Edilme Durumu\n- [ ] Unit testler yazıldı/güncellendi\n- [ ] Tüm testler geçiyor\n- [ ] Manuel test yapıldı\n\n## Checklist\n- [ ] Kodun stil kurallarına uygunluğu kontrol edildi\n- [ ] Self-review yapıldı\n- [ ] Kod açıklamalı (gerektiği yerlerde)\n- [ ] İlgili dokümantasyon güncellendi\n- [ ] Değişiklikler test edildi\n- [ ] Dependent değişiklikler merge edildi\n\n## Screenshots (gerekirse)\nİlgili ekran görüntüleri ekleyin.\n\n## Additional Notes\nEk notlar, bağımlılıklar, bilinen sorunlar vb.\n\"\"\"\n\nwith open(f\"{pr_template_dir}/pull_request_template.md\", \"w\", encoding=\"utf-8\") as f:\n    f.write(pr_template)\n\n# Issue template\nissue_template_dir = \".github/ISSUE_TEMPLATE\"\nos.makedirs(issue_template_dir, exist_ok=True)\n\nbug_template = \"\"\"---\nname: Bug Report\nabout: Bir bug bildirmek için bu template'i kullanın\ntitle: '[BUG] '\nlabels: bug\nassignees: ''\n---\n\n## Bug Açıklaması\nKarşılaştığınız bug'ı açık ve kısa bir şekilde tanımlayın.\n\n## Tekrar Etme Adımları\nBug'ı tekrar etmek için gereken adımlar:\n1. '...' sayfasına git\n2. '...' butonuna tıkla\n3. '...' alanında aşağı kaydır\n4. Hata görüntülenir\n\n## Beklenen Davranış\nNe olmasını bekliyordunuz?\n\n## Ekran Görüntüleri\nUygunsa, sorunu açıklamaya yardımcı olacak ekran görüntüleri ekleyin.\n\n## Ortam Bilgileri\n- OS: [örn. iOS]\n- Python Version: [örn. 3.9]\n- Browser [örn. chrome, safari]\n- Version [örn. 22]\n\n## Ek Bağlam\nBug hakkında başka herhangi bir bilgi.\n\"\"\"\n\nwith open(f\"{issue_template_dir}/bug_report.md\", \"w\", encoding=\"utf-8\") as f:\n    f.write(bug_template)\n\n# Test dosyası oluşturalım\ntest_content = \"\"\"\nimport pytest\nimport pandas as pd\nimport sys\nimport os\n\n# src klasörünü path'e ekle\nsys.path.insert(0, os.path.join(os.path.dirname(__file__), '..', 'src'))\n\nfrom data.make_dataset import load_raw_data, basic_data_validation\nfrom features.build_features import create_age_groups, encode_categorical_features\n\nclass TestDataModule:\n    \\\"\\\"\\\"Veri modülü testleri.\\\"\\\"\\\"\n\n    def test_basic_data_validation(self):\n        \\\"\\\"\\\"Veri doğrulama fonksiyonunu test eder.\\\"\\\"\\\"\n        # Test verisi oluştur\n        test_df = pd.DataFrame({\n            'age': [25, 30, None, 45],\n            'income': [50000, 60000, 70000, 80000],\n            'city': ['Istanbul', 'Ankara', 'Istanbul', 'Izmir']\n        })\n\n        result = basic_data_validation(test_df)\n\n        # Null sayısını kontrol et\n        assert result['null_counts']['age'] == 1\n        assert result['null_counts']['income'] == 0\n\n        # Veri tiplerini kontrol et\n        assert 'age' in result['data_types']\n        assert 'income' in result['data_types']\n\nclass TestFeatureModule:\n    \\\"\\\"\\\"Özellik mühendisliği modülü testleri.\\\"\\\"\\\"\n\n    def test_create_age_groups(self):\n        \\\"\\\"\\\"Yaş grupları oluşturma fonksiyonunu test eder.\\\"\\\"\\\"\n        test_df = pd.DataFrame({\n            'age': [20, 30, 40, 60],\n            'income': [40000, 50000, 60000, 70000]\n        })\n\n        result_df = create_age_groups(test_df)\n\n        # Yeni sütunun eklendiğini kontrol et\n        assert 'age_group' in result_df.columns\n\n        # Kategorilerin doğruluğunu kontrol et\n        expected_groups = ['young', 'adult', 'middle', 'senior']\n        for group in result_df['age_group'].dropna():\n            assert group in expected_groups\n\n    def test_encode_categorical_features(self):\n        \\\"\\\"\\\"Kategorik özellik kodlama fonksiyonunu test eder.\\\"\\\"\\\"\n        test_df = pd.DataFrame({\n            'city': ['Istanbul', 'Ankara', 'Istanbul', 'Izmir'],\n            'age': [25, 30, 35, 40]\n        })\n\n        result_df, encoders = encode_categorical_features(test_df, ['city'])\n\n        # Kodlama yapıldığını kontrol et\n        assert result_df['city'].dtype in ['int64', 'int32']\n\n        # Encoder'ın döndürüldüğünü kontrol et\n        assert 'city' in encoders\n        assert hasattr(encoders['city'], 'classes_')\n\nif __name__ == \"__main__\":\n    pytest.main([__file__])\n\"\"\"\n\nwith open(\"tests/test_modules.py\", \"w\", encoding=\"utf-8\") as f:\n    f.write(test_content)\n\nprint(\"GitHub workflow dosyaları ve testler oluşturuldu.\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 8.2. GitHub Flow vs Git Flow\n\n**GitHub Flow (Basit):**\n1. `main` branch her zaman deployable\n2. Yeni özellik için branch oluştur\n3. Değişiklikleri commit et ve push et\n4. Pull Request aç\n5. Code review yap\n6. Merge et ve branch'i sil\n\n**Git Flow (Karmaşık):**\n- `main`: Production-ready kod\n- `develop`: Geliştirme branch'i\n- `feature/*`: Özellik branch'leri\n- `release/*`: Release hazırlığı\n- `hotfix/*`: Acil düzeltmeler"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 9. İleri Düzey Git Teknikleri\n\n### 9.1. Git Hooks ve Automation"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# Pre-commit hook oluşturalım (kendi hook sistemimizi simüle edelim)\nhooks_dir = \".git/hooks\"\nif os.path.exists(hooks_dir):\n    pre_commit_hook = \"\"\"#!/bin/sh\n# Pre-commit hook - kod kalitesi kontrolleri\n\necho \"Pre-commit hook çalışıyor...\"\n\n# Python dosyalarını kontrol et\necho \"Python kod stili kontrol ediliyor...\"\nif command -v flake8 >/dev/null 2>&1; then\n    flake8 src/ tests/\n    if [ $? -ne 0 ]; then\n        echo \"❌ Flake8 hatası buldu. Commit iptal edildi.\"\n        exit 1\n    fi\nfi\n\n# Büyük dosyaları kontrol et\necho \"Büyük dosyalar kontrol ediliyor...\"\ngit diff --cached --name-only | while read file; do\n    if [ -f \"$file\" ]; then\n        size=$(stat -f%z \"$file\" 2>/dev/null || stat -c%s \"$file\" 2>/dev/null)\n        if [ $size -gt 10485760 ]; then  # 10MB\n            echo \"❌ Hata: $file dosyası çok büyük (>10MB)\"\n            exit 1\n        fi\n    fi\ndone\n\necho \"✅ Pre-commit kontrolleri başarılı!\"\nexit 0\n\"\"\"\n\n    try:\n        with open(f\"{hooks_dir}/pre-commit\", \"w\") as f:\n            f.write(pre_commit_hook)\n        os.chmod(f\"{hooks_dir}/pre-commit\", 0o755)\n        print(\"Pre-commit hook oluşturuldu.\")\n    except:\n        print(\"Hook oluşturulamadı (normal davranış).\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 9.2. Git Alias'ları ve Produktivite İpuçları"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# Faydalı git alias'ları konfigüre edelim\nuseful_aliases = [\n    ('st', 'status'),\n    ('co', 'checkout'),\n    ('br', 'branch'),\n    ('ci', 'commit'),\n    ('unstage', 'reset HEAD --'),\n    ('last', 'log -1 HEAD'),\n    ('visual', '!gitk'),\n    ('tree', 'log --graph --oneline --all'),\n    ('aliases', 'config --get-regexp alias'),\n    ('cleanup', 'branch --merged | grep -v \"\\\\*\\\\|main\\\\|develop\" | xargs -n 1 git branch -d')\n]\n\nprint(\"Faydalı Git alias'ları:\")\nfor alias, command in useful_aliases:\n    run_git_command(f'config alias.{alias} \"{command}\"', f'Alias ekleniyor: {alias}', False)\n    print(f\"git {alias} -> git {command}\")\n\n# Alias'ları test edelim\nrun_git_command(\"aliases\", \"Yapılandırılmış alias'lar\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 9.3. Git Bisect: Bug Hunting"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# Git bisect için örnek senaryo oluşturalım\nprint(\"\\n=== GIT BISECT DEMO ===\")\n\n# Birkaç commit oluşturalım, aralarında bug introducer olacak\ndef create_commits_with_bug():\n    \"\"\"Bug içeren commit serisi oluşturur.\"\"\"\n\n    # v1.0 - çalışan kod\n    working_code = \"\"\"\ndef calculate_average(numbers):\n    \\\"\\\"\\\"Sayıların ortalamasını hesaplar.\\\"\\\"\\\"\n    if not numbers:\n        return 0\n    return sum(numbers) / len(numbers)\n\ndef calculate_sum(numbers):\n    \\\"\\\"\\\"Sayıların toplamını hesaplar.\\\"\\\"\\\"\n    return sum(numbers)\n\nif __name__ == \"__main__\":\n    test_numbers = [1, 2, 3, 4, 5]\n    print(f\"Ortalama: {calculate_average(test_numbers)}\")\n    print(f\"Toplam: {calculate_sum(test_numbers)}\")\n\"\"\"\n\n    with open(\"src/calculator.py\", \"w\") as f:\n        f.write(working_code)\n    run_git_command(\"add .\", \"\", False)\n    run_git_command('commit -m \"v1.0: Hesaplama modülü eklendi\"', \"\", False)\n\n    # v1.1 - özellik ekleme\n    enhanced_code = working_code.replace(\n        'if __name__ == \"__main__\":',\n        '''def calculate_median(numbers):\n    \"\"\"Sayıların medyanını hesaplar.\"\"\"\n    if not numbers:\n        return 0\n    sorted_numbers = sorted(numbers)\n    n = len(sorted_numbers)\n    if n % 2 == 0:\n        return (sorted_numbers[n//2-1] + sorted_numbers[n//2]) / 2\n    return sorted_numbers[n//2]\n\nif __name__ == \"__main__\":'''\n    )\n\n    with open(\"src/calculator.py\", \"w\") as f:\n        f.write(enhanced_code)\n    run_git_command(\"add .\", \"\", False)\n    run_git_command('commit -m \"v1.1: Medyan hesaplama eklendi\"', \"\", False)\n\n    # v1.2 - BUG! (sıfıra bölme hatası)\n    buggy_code = enhanced_code.replace(\n        'return sum(numbers) / len(numbers)',\n        'return sum(numbers) / (len(numbers) - 1)  # BUG: Off-by-one error!'\n    )\n\n    with open(\"src/calculator.py\", \"w\") as f:\n        f.write(buggy_code)\n    run_git_command(\"add .\", \"\", False)\n    run_git_command('commit -m \"v1.2: Performans optimizasyonu\"', \"\", False)\n\n    # v1.3 - başka özellik\n    with open(\"src/calculator.py\", \"a\") as f:\n        f.write(\"\\n\\n# Versiyon 1.3 - Yeni yorum satırı\\n\")\n    run_git_command(\"add .\", \"\", False)\n    run_git_command('commit -m \"v1.3: Dokümantasyon güncellendi\"', \"\", False)\n\ncreate_commits_with_bug()\n\nprint(\"Bug içeren commit serisi oluşturuldu.\")\nrun_git_command(\"log --oneline\", \"Son commit'ler\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 9.4. Advanced Git Commands"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "# Diğer önemli Git komutları\nprint(\"\\n=== GELİŞMİŞ GIT KOMUTLARI ===\")\n\n# Git reflog - kayıp commit'leri bulma\nrun_git_command(\"reflog --oneline -10\", \"Son 10 Git işlemi (reflog)\")\n\n# Git cherry-pick için örnek\nrun_git_command(\"checkout -b hotfix-branch\", \"Hotfix dalı oluşturuluyor\")\n\n# Hotfix commit\nwith open(\"src/calculator.py\", \"r\") as f:\n    content = f.read()\n\ncontent = content.replace(\"# BUG: Off-by-one error!\", \"# FIXED: Restored original logic\")\ncontent = content.replace(\"len(numbers) - 1\", \"len(numbers)\")\n\nwith open(\"src/calculator.py\", \"w\") as f:\n    f.write(content)\n\nrun_git_command(\"add .\", \"\", False)\nrun_git_command('commit -m \"Hotfix: Ortalama hesaplama hatası düzeltildi\"', \"Hotfix commit'i\")\n\n# Ana dala dönüp cherry-pick yapma\nrun_git_command(\"checkout main\", \"Ana dala dönüş\")\nrun_git_command(\"cherry-pick hotfix-branch\", \"Hotfix'i ana dala cherry-pick\")"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## 10. En İyi Uygulamalar ve Pratik İpuçları\n\n### 10.1. Commit Message Kuralları"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "print(\"\\n=== COMMIT MESSAGE EN İYİ UYGULAMALARI ===\")\n\ncommit_message_guide = \"\"\"\n# İYİ COMMIT MESAJI YAPISI:\n\n# Başlık (50 karakter veya daha az)\n# |<----  50 karakter sınırını göstermek için  ---->|\n\n# Boş satır\n\n# Gövde (72 karakter satır uzunluğu)\n# |<----   72 karakter sınırını göstermek için    ---->|\n# Neden bu değişikliğin gerekli olduğunu açıklayın.\n# Neyi değil, NEDEN değiştirdiğinizi açıklayın.\n#\n# - Maddeler halinde yazabilirsiniz\n# - Çok madde varsa pull request açın\n#\n# Footer'da issue referansları:\n# Fixes: #123\n# Closes: #456\n# Related: #789\n\n# ÖRNEKLER:\n\n# ✅ İYİ ÖRNEKLER:\n# \"Müşteri churn modelinde özellik seçimi iyileştirildi\"\n# \"API endpoint'inde authentication bug'ı düzeltildi\"\n# \"Docker container'ı için memory limit ayarlandı\"\n\n# ❌ KÖTÜ ÖRNEKLER:\n# \"fix\" (çok genel)\n# \"minor changes\" (bilgi vermiyor)\n# \"asdasdas\" (anlamsız)\n# \"WIP work in progress\" (commit etmeyin)\n\n# TİP PREFIKSLERI:\n# feat: Yeni özellik\n# fix: Bug düzeltmesi\n# docs: Dokümantasyon\n# style: Kod formatı (işlevsellik değişikliği yok)\n# refactor: Refactoring (bug fix veya yeni özellik değil)\n# test: Test ekleme/düzeltme\n# chore: Build process veya auxiliary tool değişiklikleri\n\"\"\"\n\nprint(commit_message_guide)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### 10.2. Git Workflow Best Practices"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "workflow_guide = \"\"\"\n=== VERİ BİLİMİ PROJELERİ İÇİN GIT WORKFLOW ===\n\n1. BRANCH STRATEJİSİ:\n   ├── main (production-ready)\n   ├── develop (integration branch)\n   ├── feature/model-improvements\n   ├── feature/data-preprocessing\n   ├── experiment/new-algorithm\n   └── hotfix/critical-bug\n\n2. NAMING CONVENTIONS:\n   • feature/açıklayıcı-isim\n   • experiment/algoritma-adı\n   • hotfix/kısa-açıklama\n   • docs/güncelleme-konusu\n\n3. COMMIT SIKLIĞI:\n   • Küçük, atomik commit'ler yapın\n   • Her commit çalışan kod olmalı\n   • Günde birden fazla commit normal\n   • WIP commit'leri yapmayın\n\n4. PULL REQUEST SÜRECİ:\n   • Her PR bir konuya odaklanmalı\n   • Self-review yapın\n   • Açıklayıcı başlık ve açıklama\n   • Screenshot ekleyin (görsel değişiklik varsa)\n   • CI/CD geçmesini bekleyin\n\n5. CODE REVIEW:\n   • Constructive feedback verin\n   • Kodun logic'ini anlayın\n   • Best practice'leri kontrol edin\n   • Documentation yeterli mi?\n\n6. VERİ VE MODEL YÖNETİMİ:\n   • Büyük dosyaları Git'e eklemeyin\n   • DVC veya Git LFS kullanın\n   • Model versiyonlarını tag'leyin\n   • Experiment metadata'sını kaydedin\n\n7. GÜVENLİK:\n   • API key'leri commit etmeyin\n   • .env dosyalarını .gitignore'a ekleyin\n   • Hassas verileri repository'de tutmayın\n   • Pre-commit hook'ları kullanın\n\"\"\"\n\nprint(workflow_guide)"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### Alıştırma: Kapsamlı Git Senaryosu\n\nAşağıdaki senaryoyu gerçekleştirin:\n\n1. **Yeni özellik dalı:** `feature/model-evaluation` oluşturun\n2. **Model değerlendirme modülü** ekleyin (cross-validation, metrics)\n3. **Conflict oluşturun:** Aynı dosyayı main'de de değiştirin\n4. **Conflict çözün:** Manual veya tool kullanarak\n5. **Stash kullanın:** Yarım kalmış değişiklikleri saklayın\n6. **Cherry-pick:** Başka daldan bir commit alın\n7. **Tag oluşturun:** Stable versiyonu işaretleyin\n8. **Clean up:** Gereksiz dalları silin"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "metadata": {},
      "outputs": [],
      "source": [
        "def comprehensive_git_exercise():\n    \"\"\"Kapsamlı Git alıştırması.\"\"\"\n    print(\"\\n=== KAPSAMLI GIT ALIŞTIRMASİ ===\")\n\n    # 1. Yeni özellik dalı\n    run_git_command(\"checkout -b feature/model-evaluation\", \"Model değerlendirme dalı\")\n\n    # 2. Model değerlendirme modülü\n    evaluation_module = \"\"\"\nimport numpy as np\nfrom sklearn.model_selection import cross_val_score, StratifiedKFold\nfrom sklearn.metrics import accuracy_score, precision_score, recall_score, f1_score\nfrom sklearn.metrics import confusion_matrix, classification_report\nimport matplotlib.pyplot as plt\nimport seaborn as sns\n\nclass ModelEvaluator:\n    \\\"\\\"\\\"Model değerlendirme sınıfı.\\\"\\\"\\\"\n\n    def __init__(self, model):\n        self.model = model\n        self.cv_scores = None\n        self.test_metrics = None\n\n    def cross_validate(self, X, y, cv_folds=5):\n        \\\"\\\"\\\"Cross-validation ile model değerlendirme.\\\"\\\"\\\"\n        skf = StratifiedKFold(n_splits=cv_folds, shuffle=True, random_state=42)\n\n        # Farklı metrikler için cross-validation\n        metrics = ['accuracy', 'precision', 'recall', 'f1']\n        cv_results = {}\n\n        for metric in metrics:\n            scores = cross_val_score(self.model, X, y, cv=skf, scoring=metric)\n            cv_results[metric] = {\n                'scores': scores,\n                'mean': scores.mean(),\n                'std': scores.std()\n            }\n\n        self.cv_scores = cv_results\n        return cv_results\n\n    def evaluate_test_set(self, X_test, y_test):\n        \\\"\\\"\\\"Test seti üzerinde detaylı değerlendirme.\\\"\\\"\\\"\n        y_pred = self.model.predict(X_test)\n\n        metrics = {\n            'accuracy': accuracy_score(y_test, y_pred),\n            'precision': precision_score(y_test, y_pred, average='weighted'),\n            'recall': recall_score(y_test, y_pred, average='weighted'),\n            'f1': f1_score(y_test, y_pred, average='weighted')\n        }\n\n        self.test_metrics = metrics\n        return metrics\n\n    def plot_confusion_matrix(self, X_test, y_test, save_path=None):\n        \\\"\\\"\\\"Confusion matrix çizer.\\\"\\\"\\\"\n        y_pred = self.model.predict(X_test)\n        cm = confusion_matrix(y_test, y_pred)\n\n        plt.figure(figsize=(8, 6))\n        sns.heatmap(cm, annot=True, fmt='d', cmap='Blues')\n        plt.title('Confusion Matrix')\n        plt.xlabel('Predicted')\n        plt.ylabel('Actual')\n\n        if save_path:\n            plt.savefig(save_path, dpi=300, bbox_inches='tight')\n\n        plt.show()\n\n    def generate_report(self):\n        \\\"\\\"\\\"Kapsamlı değerlendirme raporu oluşturur.\\\"\\\"\\\"\n        report = \"=== MODEL DEĞERLENDİRME RAPORU ===\\\\n\\\\n\"\n\n        if self.cv_scores:\n            report += \"Cross-Validation Sonuçları:\\\\n\"\n            for metric, results in self.cv_scores.items():\n                report += f\"{metric.capitalize()}: {results['mean']:.4f} (+/- {results['std']*2:.4f})\\\\n\"\n\n        if self.test_metrics:\n            report += \"\\\\nTest Seti Sonuçları:\\\\n\"\n            for metric, value in self.test_metrics.items():\n                report += f\"{metric.capitalize()}: {value:.4f}\\\\n\"\n\n        return report\n\nif __name__ == \"__main__\":\n    print(\"Model değerlendirme modülü hazır.\")\n\"\"\"\n\n    with open(\"src/models/evaluate_model.py\", \"w\", encoding=\"utf-8\") as f:\n        f.write(evaluation_module)\n\n    run_git_command(\"add .\", \"\", False)\n    run_git_command('commit -m \"Model değerlendirme modülü eklendi\\\\n\\\\n- Cross-validation desteği\\\\n- Test seti değerlendirmesi\\\\n- Confusion matrix görselleştirmesi\\\\n- Kapsamlı rapor oluşturma\"',\n                    \"Model evaluation commit\")\n\n    # 3-4. Conflict oluşturma ve çözme\n    run_git_command(\"checkout main\", \"Ana dala geçiş\")\n\n    # Ana dalda aynı dosyayı farklı şekilde değiştir\n    simple_eval = \"\"\"\ndef simple_accuracy(y_true, y_pred):\n    \\\"\\\"\\\"Basit accuracy hesaplama.\\\"\\\"\\\"\n    correct = sum(1 for true, pred in zip(y_true, y_pred) if true == pred)\n    return correct / len(y_true)\n\nprint(\"Basit değerlendirme modülü\")\n\"\"\"\n\n    with open(\"src/models/evaluate_model.py\", \"w\") as f:\n        f.write(simple_eval)\n\n    run_git_command(\"add .\", \"\", False)\n    run_git_command('commit -m \"Basit model değerlendirme eklendi\"', \"\", False)\n\n    # Conflict oluştur ve çöz\n    print(\"Conflict oluşturuluyor ve çözülüyor...\")\n    run_git_command(\"merge feature/model-evaluation\", \"Conflict oluşturma\", False)\n    run_git_command(\"checkout --theirs src/models/evaluate_model.py\", \"Gelişmiş versiyon seçiliyor\", False)\n    run_git_command(\"add .\", \"\", False)\n    run_git_command('commit -m \"Merge conflict çözüldü: Gelişmiş model evaluation korundu\"', \"\", False)\n\n    # 7. Tag oluşturma\n    run_git_command(\"tag -a v1.0.0 -m 'Stable release: Basic ML pipeline completed'\", \"Stable versiyon tag'i\")\n    run_git_command(\"tag\", \"Mevcut tag'lar\")\n\n    print(\"✅ Kapsamlı Git alıştırması tamamlandı!\")\n\n# Alıştırmayı çalıştır\ncomprehensive_git_exercise()"
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "## Haftanın Özeti\n\nBu hafta kapsamlı bir Git eğitimi tamamladık:\n\n### Öğrendiklerimiz:\n1. **Temel Git işlemleri:** init, add, commit, status, log, diff\n2. **Branching ve merging:** Feature-branch workflow, conflict çözme\n3. **Git Stash:** Geçici değişiklikleri yönetme\n4. **PyCharm entegrasyonu:** IDE üzerinden Git operasyonları\n5. **GitHub workflow:** Pull requests, code review, CI/CD\n6. **İleri düzey teknikler:** Hooks, bisect, cherry-pick, reflog\n7. **Best practices:** Commit mesajları, workflow stratejileri\n\n### Pratik Beceriler:\n- ✅ Git repository'si yönetimi\n- ✅ Conflict çözme yöntemleri\n- ✅ Stash kullanımı\n- ✅ PyCharm Git tools kullanımı\n- ✅ GitHub collaboration\n- ✅ Professional workflow patterns\n\n### Sonraki Adımlar\n\nArtık projelerinizi profesyonel seviyede versiyon kontrol altında tutabiliyorsunuz. **Hafta 2: Kod ve Veri için Test Stratejileri**'nde, yazdığımız kodun doğruluğunu garanti altına almak için test yazma disiplinini öğreneceğiz. Git ile test süreçlerini nasıl entegre edeceğimizi ve sürekli entegrasyon (CI) temellerini atacağız."
      ]
    },
    {
      "cell_type": "markdown",
      "metadata": {},
      "source": [
        "### Git Komutları Özet Tablosu\n\n| Kategori | Komut | Açıklama |\n|----------|-------|----------|\n| **Başlangıç** | `git init` | Repository başlatır |\n| | `git clone <url>` | Remote repository'yi klonlar |\n| **Temel İşlemler** | `git status` | Çalışma dizini durumu |\n| | `git add <file>` | Dosyayı staging area'ya ekler |\n| | `git commit -m \"mesaj\"` | Değişiklikleri commit eder |\n| | `git log` | Commit geçmişini gösterir |\n| **Branching** | `git branch` | Dalları listeler |\n| | `git checkout -b <branch>` | Yeni dal oluşturur ve geçer |\n| | `git merge <branch>` | Dalı birleştirir |\n| | `git branch -d <branch>` | Dalı siler |\n| **Stash** | `git stash` | Değişiklikleri saklar |\n| | `git stash pop` | Son stash'i geri getirir |\n| | `git stash list` | Stash listesini gösterir |\n| **Remote** | `git remote add origin <url>` | Remote ekler |\n| | `git push` | Değişiklikleri remote'a gönderir |\n| | `git pull` | Remote'dan değişiklikleri çeker |\n| **İleri Düzey** | `git cherry-pick <commit>` | Belirli commit'i alır |\n| | `git reflog` | Tüm Git işlemlerini gösterir |\n| | `git bisect` | Binary search ile bug bulur |\n| | `git tag <name>` | Tag oluşturur |\n\nTemizlik\nos.chdir(original_dir)\nprint(f\"\\n=== DERS TAMAMLANDI ===\")\nprint(f\"Çalışma dizini: {os.getcwd()}\")\nprint(\"✅ Hafta 1: Git ve GitHub dersi başarıyla tamamlandı!\")"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "Python 3",
      "language": "python",
      "name": "python3"
    },
    "language_info": {
      "name": "python",
      "version": "3.8.0"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 4
}