├── .gitignore ├── blog.md └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Node modules 2 | node_modules/ 3 | temp* 4 | # Logs 5 | logs/ 6 | *.log 7 | npm-debug.log* 8 | yarn-debug.log* 9 | yarn-error.log* 10 | 11 | # Build output 12 | dist/ 13 | build/ 14 | out/ 15 | 16 | # Dependency directories 17 | jspm_packages/ 18 | 19 | # OS/System files 20 | .DS_Store 21 | Thumbs.db 22 | ehthumbs.db 23 | Icon? 24 | 25 | # Environment files 26 | .env 27 | .env.local 28 | .env.*.local 29 | 30 | # IDEs and editors 31 | .vscode/ 32 | .idea/ 33 | *.sublime-workspace 34 | *.sublime-project 35 | 36 | # Optional: macOS-specific 37 | DC_STORE 38 | 39 | # Test coverage 40 | coverage/ 41 | .nyc_output/ 42 | 43 | # TypeScript 44 | *.tsbuildinfo 45 | 46 | # Misc 47 | *.tgz 48 | *.gz 49 | *.zip 50 | *.bak 51 | *.tmp 52 | 53 | # Git hooks and other config backups 54 | *.orig 55 | 56 | # Ignore lock files if not using them strictly 57 | # package-lock.json 58 | # yarn.lock 59 | -------------------------------------------------------------------------------- /blog.md: -------------------------------------------------------------------------------- 1 | # Learn Git and GitHub the Easy Way: A Beginner's Guide 2 | 3 | If you're new to coding or just starting to work on real projects, Git can seem confusing. But once you understand the basics, it becomes one of the most powerful tools you'll use every day. This guide will walk you through Git step by step, using simple examples and clear explanations. 4 | 5 | --- 6 | 7 | ## 🚀 What Is Git? 8 | 9 | Git is a free tool that helps you: 10 | 11 | - **Save versions of your code** and keep track of every change. 12 | - **Go back in time** if something breaks or you make a mistake. 13 | - **Work with others** on the same project without overwriting each other's changes. 14 | 15 | Think of Git as a smart "undo" and collaboration system for your code. 16 | 17 | --- 18 | 19 | ## 🛠️ How to Set Up Git (First-Time Only) 20 | 21 | Before you can start using Git, you need to tell Git who you are. This info gets saved with every change you make, so it's important to set it up properly. 22 | 23 | ### Step 1: Open the Terminal 24 | 25 | You need to use the terminal to enter Git commands. 26 | 27 | **If you're using VSCode:** 28 | 29 | - Go to the top menu and click: 30 | **View > Terminal** 31 | 32 | Or use the keyboard shortcut: 33 | 34 | - **Ctrl + `** (on Windows or Linux) 35 | - **Cmd + `** (on Mac) 36 | 37 | This opens the terminal panel at the bottom of the editor. 38 | 39 | **If you're using macOS and not VSCode:** 40 | 41 | - Open the built-in **Terminal app**. 42 | - Press **Cmd + Space**, type **Terminal**, and hit **Enter**. 43 | 44 | The terminal is where you'll type and run Git commands. 45 | 46 | --- 47 | 48 | ### Step 2: Set Your Name and Email 49 | 50 | Once the terminal is open, run the following commands: 51 | 52 | ```bash 53 | git config --global user.name "Your Name" 54 | git config --global user.email "you@example.com" 55 | ``` 56 | 57 | Replace `"Your Name"` with your actual name and use the email address you plan to use on GitHub. 58 | 59 | --- 60 | 61 | ### What These Commands Do 62 | 63 | - `user.name` and `user.email` tell Git who is making each change. 64 | - This information shows up next to each commit. 65 | - The `--global` flag means these settings apply to all Git projects on your computer (you only need to do this once). 66 | 67 | --- 68 | 69 | ### Check Your Git Settings 70 | 71 | To make sure your info was saved correctly, run: 72 | 73 | ```bash 74 | git config --global --list 75 | ``` 76 | 77 | This will show your name and email. 78 | 79 | To see all Git settings and where they were set from: 80 | 81 | ```bash 82 | git config --list --show-origin 83 | ``` 84 | 85 | Now you're ready to start using Git in any project! 86 | 87 | --- 88 | 89 | ## 🧾 Most Used Git Commands (And What They Do) 90 | 91 | ### Start a New Git Project 92 | 93 | ```bash 94 | git init 95 | ``` 96 | 97 | This command tells Git to start tracking your project. It creates a hidden `.git` folder inside your project. You won't usually touch this folder, but it's where Git saves all the history and settings. 98 | 99 | --- 100 | 101 | ### Check What's Going On 102 | 103 | ```bash 104 | git status 105 | ``` 106 | 107 | This shows the current state of your files — which ones are new, which ones have been changed, and which ones are ready to be saved (committed). It's a command you'll use a lot. 108 | 109 | --- 110 | 111 | ### Add Files to Be Saved 112 | 113 | Before you save your changes permanently, you need to stage them using: 114 | 115 | ```bash 116 | git add file.txt 117 | ``` 118 | 119 | This stages the file `file.txt`. 120 | 121 | To stage everything in the current folder: 122 | 123 | ```bash 124 | git add . 125 | ``` 126 | 127 | To stage everything in the entire project (no matter where you are): 128 | 129 | ```bash 130 | git add -A 131 | ``` 132 | 133 | --- 134 | 135 | ### Save the Changes (Make a Commit) 136 | 137 | ```bash 138 | git commit -m "your message here" 139 | ``` 140 | 141 | This saves all the staged changes and adds a message so you know what the change was. 142 | 143 | Good messages are short and clear, like: 144 | 145 | ```bash 146 | git commit -m "add login form" 147 | git commit -m "fix footer layout" 148 | ``` 149 | 150 | Avoid unclear messages like: 151 | 152 | ```bash 153 | git commit -m "stuff" 154 | git commit -m "things" 155 | ``` 156 | 157 | Commit messages help you remember what you did and help others understand your work too. 158 | 159 | --- 160 | 161 | ### See Your Project History 162 | 163 | ```bash 164 | git log 165 | ``` 166 | 167 | This shows all the past commits — including who made them, the message, and when. 168 | 169 | If you want a shorter version: 170 | 171 | ```bash 172 | git log --oneline 173 | ``` 174 | 175 | This shows one line per commit, so it's easier to scan quickly. 176 | 177 | --- 178 | 179 | ## 🔁 How Git Tracks Files (File States Explained) 180 | 181 | Each file in Git can be in one of several states: 182 | 183 | - **Untracked** – Git doesn't know about the file yet. 184 | - **Staged** – You've told Git to include the file in the next save (`git add`). 185 | - **Committed** – The file has been saved in the project history. 186 | - **Modified** – You've changed a file that was already saved. 187 | 188 | Understanding these states is helpful when you're figuring out what will be saved and what hasn't yet. 189 | 190 | --- 191 | 192 | ## 🧪 Try It Yourself: Your First Git Project 193 | 194 | Let's go step by step and practice everything. 195 | 196 | 1. Create a folder called `git-tutorial` and open it in VSCode. 197 | 2. Open the terminal (Ctrl + `). 198 | 3. Run this to start Git in your project: 199 | 200 | ```bash 201 | git init 202 | ``` 203 | 204 | 4. Create a file: 205 | 206 | ```bash 207 | echo "Hello Git" > main.txt 208 | ``` 209 | 210 | 5. Add the file to the staging area: 211 | 212 | ```bash 213 | git add main.txt 214 | ``` 215 | 216 | 6. Save it with a message: 217 | 218 | ```bash 219 | git commit -m "add main.txt" 220 | ``` 221 | 222 | 7. Add more files: 223 | 224 | ```bash 225 | echo "New file" > second.txt 226 | git add . 227 | git commit -m "add second.txt" 228 | ``` 229 | 230 | 8. See your history: 231 | 232 | ```bash 233 | git log --oneline 234 | ``` 235 | 236 | Now you've made multiple commits and can review your project's history. 237 | 238 | --- 239 | 240 | ## ✏️ Making Changes and Adding New Files 241 | 242 | Let's try editing and adding at the same time: 243 | 244 | 1. Edit `main.txt` and change the text. 245 | 2. Create a new folder called `notes`. 246 | 3. Inside that folder, create a file: `todo.txt`. 247 | 4. Add and commit both changes: 248 | 249 | ```bash 250 | git add . 251 | git commit -m "update main.txt and add todo.txt" 252 | ``` 253 | 254 | This shows how Git handles both modified and new files at the same time. 255 | 256 | --- 257 | 258 | ## 🧩 Using Git Inside VSCode 259 | 260 | Instead of using the terminal, you can use the Git GUI built into VSCode. 261 | 262 | - Click the Source Control icon in the sidebar (it looks like a branch). 263 | - You'll see file changes, and you can: 264 | - Stage files by clicking the "+" button 265 | - Write commit messages in the input box 266 | - Click the checkmark to commit 267 | 268 | This is helpful if you're more comfortable with a visual interface instead of using the terminal. 269 | 270 | --- 271 | 272 | ## 🧭 Going Back in Time with Git 273 | 274 | Every time you commit, Git saves a unique ID (called a hash). You can use it to go back to that version. 275 | 276 | 1. See your history: 277 | 278 | ```bash 279 | git log --oneline 280 | ``` 281 | 282 | 2. Copy the hash from a commit. 283 | 3. Move to that version: 284 | 285 | ```bash 286 | git checkout 287 | ``` 288 | 289 | While in this "detached" state, don't make changes. When you're ready to go back to the main version: 290 | 291 | ```bash 292 | git checkout main 293 | ``` 294 | 295 | --- 296 | 297 | ## ⚠️ Important Git Tips 298 | 299 | ### `git add .` vs `git add -A` 300 | 301 | - `git add .` adds changes from the current folder only. 302 | - `git add -A` adds changes from the entire project, even from other folders. 303 | 304 | To make sure you don't miss anything, use `git add -A`. 305 | 306 | --- 307 | 308 | ### Never Touch the `.git` Folder 309 | 310 | This folder stores Git's internal data. Do **not**: 311 | 312 | - Create folders inside `.git` 313 | - Run `git init` inside it 314 | - Edit or delete files in it 315 | 316 | Doing this can break your project and delete your commit history. 317 | 318 | --- 319 | 320 | ## 🎯 Practice Challenge 321 | 322 | 1. Create a new folder: `my-git-project`. 323 | 2. Open it in VSCode and open the terminal. 324 | 3. Start Git: 325 | 326 | ```bash 327 | git init 328 | ``` 329 | 330 | 4. Create a file and write something inside. 331 | 5. Add and commit it: 332 | 333 | ```bash 334 | git add . 335 | git commit -m "initial commit" 336 | ``` 337 | 338 | 6. Edit the file, create another one, and repeat the process. 339 | 7. Use `git log --oneline` to see what you've done. 340 | 341 | Repeat the process to practice. The more you use Git, the more natural it becomes. 342 | 343 | --- 344 | 345 | ## ✅ What's Next? 346 | 347 | Once you're comfortable with these basics, the next step is to learn: 348 | 349 | - **Branches** – Work on features without touching the main code. 350 | - **Merging** – Combine different branches together. 351 | - **Rebasing** – Clean up your history. 352 | - **Fixing conflicts** – Handle situations when changes overlap. 353 | 354 | That's all coming in the next guide. 355 | 356 | --- 357 | 358 | _You're doing great — Git is your friend now!_ 🙌 359 | 360 | # Git Branches, Merging, and Rebasing — A Simple Guide 361 | 362 | Now that you know the basics of Git, it's time to learn how to work on **different tasks or features without breaking your main project**. That's where **branches** come in. You'll also learn how to **merge** and **rebase** changes, which are two ways of bringing branches back together. 363 | 364 | --- 365 | 366 | ## 🌱 What Are Branches? 367 | 368 | A Git branch is like a separate copy of your project where you can work without affecting the original. This is helpful when you're adding new features, fixing bugs, or testing ideas. 369 | 370 | ### Common Branch Commands 371 | 372 | ```bash 373 | git branch # List all branches 374 | git branch new-feature # Create a new branch 375 | git checkout main # Switch to another branch 376 | git switch main # Same as checkout (Git 2.23+) 377 | git checkout -b new # Create and switch in one step 378 | git switch -c new # Same as above (Git 2.23+) 379 | ``` 380 | 381 | --- 382 | 383 | ## 🧪 Example: Creating and Switching Branches 384 | 385 | Let's walk through it. 386 | 387 | 1. Open **VSCode** and create a folder called `git-branches`. 388 | 2. Open the terminal: 389 | 390 | - **VSCode:** Click `View > Terminal` or use ` Ctrl + `` (Windows/Linux) or `Cmd + `` (Mac). 391 | - **macOS Terminal:** Press `Cmd + Space`, type **Terminal**, and hit Enter. 392 | 393 | 3. Start Git: 394 | 395 | ```bash 396 | git init 397 | ``` 398 | 399 | 4. Create a file and commit: 400 | 401 | ```bash 402 | echo "main file" > main-01.txt 403 | git add . 404 | git commit -m "add main-01.txt" 405 | ``` 406 | 407 | 5. Do the same for another file: 408 | 409 | ```bash 410 | echo "another main file" > main-02.txt 411 | git add . 412 | git commit -m "add main-02.txt" 413 | ``` 414 | 415 | 6. Create and switch to a new branch: 416 | 417 | ```bash 418 | git checkout -b feature 419 | ``` 420 | 421 | 7. Check current branch: 422 | 423 | ```bash 424 | git branch 425 | ``` 426 | 427 | 8. Add a new file in this branch: 428 | 429 | ```bash 430 | mkdir features 431 | echo "feature work" > features/feature-01.txt 432 | git add . 433 | git commit -m "add feature-01.txt" 434 | ``` 435 | 436 | 9. Switch back to `main`: 437 | 438 | ```bash 439 | git checkout main 440 | ``` 441 | 442 | Notice that `feature-01.txt` is gone — that's because each branch has its own files and changes. 443 | 444 | --- 445 | 446 | ## ⏩ Quick Practice: Create a Bugfix Branch 447 | 448 | 1. Run this to create and switch to a bugfix branch: 449 | 450 | ```bash 451 | git checkout -b bugfix 452 | ``` 453 | 454 | 2. Add and commit a new file: 455 | 456 | ```bash 457 | mkdir bugfix 458 | echo "bugfix work" > bugfix/file-01.txt 459 | git add . 460 | git commit -m "add bugfix file" 461 | ``` 462 | 463 | 3. Switch back to main: 464 | 465 | ```bash 466 | git checkout main 467 | ``` 468 | 469 | Again, the new file won't appear here. Each branch is its own world. 470 | 471 | --- 472 | 473 | ## 🔀 Merging Branches 474 | 475 | Merging brings changes from one branch into another. 476 | 477 | ### 1. Fast-Forward Merge 478 | 479 | Happens when the target branch (like `main`) has no changes of its own. Git just moves its pointer forward. 480 | 481 | Example: 482 | 483 | - You are on the `feature` branch and want to merge `main`: 484 | 485 | ```bash 486 | git merge main 487 | ``` 488 | 489 | If `main` hasn't changed, this merge is fast and clean. 490 | 491 | ### 2. Three-Way Merge 492 | 493 | Used when **both branches** have made changes. Git creates a new **merge commit** to combine both histories. 494 | 495 | Steps: 496 | 497 | 1. Switch to the branch you want to merge into: 498 | 499 | ```bash 500 | git checkout main 501 | ``` 502 | 503 | 2. Make sure you're on the right branch: 504 | 505 | ```bash 506 | git branch 507 | ``` 508 | 509 | 3. Merge the feature branch into it: 510 | 511 | ```bash 512 | git merge feature 513 | ``` 514 | 515 | 4. See the result: 516 | 517 | ```bash 518 | git log --oneline 519 | ``` 520 | 521 | Look for something like: 522 | 523 | ```bash 524 | (HEAD -> main, feature) 525 | ``` 526 | 527 | That means both branches point to the same commit. 528 | 529 | --- 530 | 531 | ### 🧪 Practice: Merge `main` into `bugfix` 532 | 533 | 1. Switch to `bugfix`: 534 | 535 | ```bash 536 | git checkout bugfix 537 | ``` 538 | 539 | 2. Merge `main` (this will create a merge commit): 540 | 541 | ```bash 542 | git merge main 543 | ``` 544 | 545 | Git may open a text editor (like Vim or Nano) to confirm the commit message. 546 | 547 | #### In VSCode GUI: 548 | 549 | - You'll see the message box in the Source Control panel. Just click **Commit**. 550 | 551 | #### In Vim: 552 | 553 | - Press `i` to edit. 554 | - Press `Esc`, type `:wq`, and hit Enter to save and quit. 555 | 556 | #### In Nano: 557 | 558 | - Type your message. 559 | - Press `Ctrl+O` then `Enter` to save. 560 | - Press `Ctrl+X` to exit. 561 | 562 | 3. Now go back to `main` and merge `bugfix`: 563 | 564 | ```bash 565 | git checkout main 566 | git merge bugfix 567 | ``` 568 | 569 | 4. Check history: 570 | 571 | ```bash 572 | git log --oneline 573 | ``` 574 | 575 | 5. Check current status: 576 | 577 | ```bash 578 | git status 579 | ``` 580 | 581 | --- 582 | 583 | ## 🧹 Deleting Branches 584 | 585 | Once a branch is merged, you can safely delete it. 586 | 587 | ```bash 588 | git branch -d branch-name 589 | ``` 590 | 591 | If it's **not merged yet**, Git will stop you from deleting it by accident. 592 | 593 | To force-delete: 594 | 595 | ```bash 596 | git branch -D branch-name 597 | ``` 598 | 599 | ### Example: 600 | 601 | ```bash 602 | git checkout main 603 | git branch -d feature 604 | git branch -d bugfix 605 | ``` 606 | 607 | Create a test branch: 608 | 609 | ```bash 610 | git checkout -b test 611 | echo "test" > test.txt 612 | git add . 613 | git commit -m "add test file" 614 | ``` 615 | 616 | Now delete it from `main`: 617 | 618 | ```bash 619 | git checkout main 620 | git branch -d test # Git warns it's not merged 621 | git branch -D test # Force delete 622 | ``` 623 | 624 | --- 625 | 626 | ## 🔁 Why Merge `main` into Feature? 627 | 628 | Sometimes your teammates update `main` while you're working on a feature. Merging `main` into your branch helps you: 629 | 630 | - **Get the latest updates** 631 | - **Solve conflicts early** 632 | - **Avoid surprises later when merging back** 633 | 634 | --- 635 | 636 | ## 📏 What Is Rebase? 637 | 638 | Rebase is another way to bring changes from one branch into another. But instead of merging, it **moves your commits** and creates a clean, straight timeline. 639 | 640 | ### When to Use It? 641 | 642 | - To make history cleaner. 643 | - **Avoid on shared/public branches** like `main` — it changes history and can confuse others. 644 | 645 | --- 646 | 647 | ### Rebase Example (Instead of Merging) 648 | 649 | 1. Create a new project: 650 | 651 | ```bash 652 | mkdir git-rebase 653 | cd git-rebase 654 | git init 655 | ``` 656 | 657 | 2. Repeat the same steps as before — make a `main`, `feature`, and `bugfix` branch. 658 | 659 | 3. In `feature` or `bugfix`, instead of merging: 660 | 661 | ```bash 662 | git rebase main 663 | ``` 664 | 665 | Now your branch will be updated with `main`'s changes, and your commits will be placed on top. 666 | 667 | Compare this to the `git-branches` project. The commit history is **cleaner**, but the result is the same. 668 | 669 | Some teams prefer rebase, others prefer merge. At work, you usually follow team rules. 670 | 671 | --- 672 | 673 | ## 🧑‍💻 Using VSCode for Branching & Merging 674 | 675 | You can do all of this in VSCode without typing commands. 676 | 677 | - Use the Source Control panel. 678 | - Click the "..." menu to create branches, switch, and merge. 679 | - When merging, VSCode will often auto-commit for you. 680 | - It's quicker and easier, especially for beginners. 681 | 682 | --- 683 | 684 | ## 🧠 Git Challenge: Branches & Merging 685 | 686 | Try this on your own: 687 | 688 | 1. Create a folder: `my-branch-project` 689 | 2. Open it in VSCode and start Git: 690 | 691 | ```bash 692 | git init 693 | ``` 694 | 695 | 3. Add and commit a couple of files in `main`. 696 | 4. Create `feature` and `bugfix` branches: 697 | 698 | ```bash 699 | git checkout -b feature 700 | git checkout -b bugfix 701 | ``` 702 | 703 | 5. Add different files in each branch and commit them. 704 | 6. Merge `main` into `feature`, then merge `feature` into `main`. 705 | 7. Do the same with `bugfix`, but try **rebase** instead of merge. 706 | 8. Try deleting the branches. 707 | 9. Create a `test` branch, commit something, and practice forced deletion. 708 | 709 | --- 710 | 711 | ## ✅ Summary 712 | 713 | - Use **branches** to safely work on features. 714 | - Use **merge** to combine branches. 715 | - Use **rebase** to clean up history (only when it's safe). 716 | - Use **VSCode** to manage Git without the terminal if you prefer visuals. 717 | 718 | With practice, all of this becomes second nature! 719 | 720 | --- 721 | 722 | _Keep practicing — you're one branch away from mastering Git!_ 🌿 723 | 724 | # Git Deep Dive: Config, Ignore, Stash, Reset, and Recovery 725 | 726 | Now that you're comfortable with the basics of Git and branches, let's explore some **important Git tools and tricks** that will make your work easier and safer. In this guide, you'll learn how to: 727 | 728 | - Use global and local Git settings 729 | - Ignore files with `.gitignore` 730 | - Stash temporary changes 731 | - Understand HEAD and detached HEAD 732 | - Use reflog to recover lost commits 733 | - Undo and reset changes safely 734 | 735 | --- 736 | 737 | ## 🔧 Git Config (Global vs Local) 738 | 739 | When using Git, it's important to tell Git who you are. You can do this **globally** (for all projects) or **locally** (just for one project). 740 | 741 | ### Global Git Config 742 | 743 | To set your name and email globally, open the terminal and run: 744 | 745 | ```bash 746 | git config --global user.name "Your Name" 747 | git config --global user.email "your@email.com" 748 | ``` 749 | 750 | This will apply to **all Git projects** on your computer. 751 | 752 | ### Local Git Config 753 | 754 | If you want to use a **different name or email in just one project**, you can set it locally: 755 | 756 | ```bash 757 | git config --local user.name "Another Name" 758 | git config --local user.email "another@email.com" 759 | ``` 760 | 761 | These settings are stored inside the `.git/config` file in your project folder. 762 | 763 | You can view local settings with: 764 | 765 | ```bash 766 | git config --local --list 767 | ``` 768 | 769 | Or open the file `.git/config` in any text editor. 770 | 771 | --- 772 | 773 | ### Extra: Customize Default Branch Name 774 | 775 | By default, Git uses `main` or `master` as the first branch name. But you can set your own: 776 | 777 | ```bash 778 | git config --global init.defaultBranch shakeAndBake 779 | ``` 780 | 781 | Now all new Git projects will start with a branch named `shakeAndBake`. It's great for teams who follow specific naming rules. 782 | 783 | --- 784 | 785 | ## 🚫 Ignoring Files with `.gitignore` 786 | 787 | Some files don't belong in your Git history — like passwords, log files, or generated files. 788 | 789 | Create a `.gitignore` file in your project and add filenames or patterns you want Git to ignore. 790 | 791 | Example: 792 | 793 | ```bash 794 | .env 795 | node_modules/ 796 | *.log 797 | ``` 798 | 799 | Git will **not track** these files, and they won't show up in `git status`. 800 | 801 | --- 802 | 803 | ### Practice: Try It Yourself 804 | 805 | 1. Create a project and run: 806 | 807 | ```bash 808 | git init 809 | ``` 810 | 811 | 2. Create a file and commit it: 812 | 813 | ```bash 814 | echo "hello" > main-01.txt 815 | git add . 816 | git commit -m "initial commit" 817 | ``` 818 | 819 | 3. Create a `.gitignore` file and add: 820 | 821 | ```bash 822 | .env 823 | ``` 824 | 825 | 4. Create a `.env` file with: 826 | 827 | ```bash 828 | SECRET_KEY=supersecret 829 | ``` 830 | 831 | 5. Run: 832 | 833 | ```bash 834 | git status 835 | ``` 836 | 837 | You'll see `.env` is ignored — it won't be staged or committed. 838 | 839 | --- 840 | 841 | ## 👜 Git Stash: Save Work for Later 842 | 843 | Sometimes you need to switch tasks but don't want to commit unfinished work. `git stash` helps with that. 844 | 845 | - Save changes: 846 | 847 | ```bash 848 | git stash 849 | ``` 850 | 851 | - Save with a message: 852 | 853 | ```bash 854 | git stash push -m "WIP: fixing button style" 855 | ``` 856 | 857 | - See stash list: 858 | 859 | ```bash 860 | git stash list 861 | ``` 862 | 863 | - Reapply the last stash and remove it: 864 | 865 | ```bash 866 | git stash pop 867 | ``` 868 | 869 | - Reapply without removing: 870 | 871 | ```bash 872 | git stash apply 873 | ``` 874 | 875 | - Apply a specific stash: 876 | 877 | ```bash 878 | git stash pop stash@{0} 879 | ``` 880 | 881 | Stash only works if your project has at least one commit. Also, it only saves **tracked files**. 882 | 883 | --- 884 | 885 | ## 📍 Understanding HEAD and Detached HEAD 886 | 887 | ### HEAD 888 | 889 | HEAD is a pointer that shows **where you are** in your Git history. Usually, it points to the latest commit on your current branch. 890 | 891 | When you make a new commit, HEAD moves forward. 892 | 893 | ### Detached HEAD 894 | 895 | If you checkout a **specific commit** (instead of a branch), HEAD gets "detached." 896 | 897 | Example: 898 | 899 | ```bash 900 | git checkout abc123 901 | ``` 902 | 903 | Now you're not on any branch. Any commits made now will not belong to a branch — they're "orphaned." 904 | 905 | To save your work: 906 | 907 | ```bash 908 | git checkout -b new-branch 909 | ``` 910 | 911 | That creates a new branch and attaches HEAD to it again. 912 | 913 | 💡 Use `git log` or `git show ` to view a commit instead of checking it out, so you avoid detached HEAD mode. 914 | 915 | --- 916 | 917 | ## 🧭 Git Reflog: Recover Lost Commits 918 | 919 | Made a mistake? Deleted a branch? Don't panic — `git reflog` can help. 920 | 921 | ```bash 922 | git reflog 923 | ``` 924 | 925 | This shows **everything** Git has done — every branch switch, commit, reset, etc. You can use it to recover lost commits: 926 | 927 | 1. Copy the commit hash from `git reflog`. 928 | 2. Checkout that commit or branch: 929 | 930 | ```bash 931 | git checkout 932 | git checkout -b recovered-branch 933 | ``` 934 | 935 | Think of `git log` as your official history, and `git reflog` as your full activity log. 936 | 937 | --- 938 | 939 | ## ♻️ Git Reset: Undoing Commits 940 | 941 | Git reset helps you **undo commits** or **unstage files**. 942 | 943 | ### Undo the Last Commit (keep changes staged): 944 | 945 | ```bash 946 | git reset --soft HEAD~1 947 | ``` 948 | 949 | ### Undo and discard changes completely: 950 | 951 | ```bash 952 | git reset --hard HEAD~1 953 | ``` 954 | 955 | ### Reset to a specific commit: 956 | 957 | ```bash 958 | git reset --hard 959 | ``` 960 | 961 | ### Unstage a file: 962 | 963 | ```bash 964 | git reset filename.txt 965 | ``` 966 | 967 | ### Unstage all files: 968 | 969 | ```bash 970 | git reset 971 | ``` 972 | 973 | 💡 HEAD~1 means "one commit before the current one". HEAD~2 would mean "two commits back". 974 | 975 | --- 976 | 977 | ## 🔙 Git Restore and Checkout 978 | 979 | To undo changes **you haven't staged yet**, use: 980 | 981 | ```bash 982 | git restore filename.txt 983 | ``` 984 | 985 | To discard all unstaged changes: 986 | 987 | ```bash 988 | git restore . 989 | ``` 990 | 991 | Or use the older version: 992 | 993 | ```bash 994 | git checkout -- filename.txt 995 | git checkout . 996 | ``` 997 | 998 | Both do the same, but `git restore` is newer and easier to read. 999 | 1000 | --- 1001 | 1002 | ## 🧹 Cleaning Untracked Files 1003 | 1004 | Untracked files are files Git doesn't know about (you haven't added them). 1005 | 1006 | ### Preview what will be deleted: 1007 | 1008 | ```bash 1009 | git clean -dn 1010 | ``` 1011 | 1012 | ### Actually delete untracked files: 1013 | 1014 | ```bash 1015 | git clean -df 1016 | ``` 1017 | 1018 | Be careful — this **cannot be undone**. 1019 | 1020 | --- 1021 | 1022 | ## 🔥 Deleting Unmerged Branches 1023 | 1024 | If you try to delete a branch that hasn't been merged: 1025 | 1026 | ```bash 1027 | git branch -d branch-name 1028 | ``` 1029 | 1030 | Git will stop you. 1031 | 1032 | To force delete: 1033 | 1034 | ```bash 1035 | git branch -D branch-name 1036 | ``` 1037 | 1038 | The commits are still saved (for a while) and can be recovered using `git reflog`. 1039 | 1040 | Tips: 1041 | 1042 | - Merge important changes before deleting 1043 | - Create a backup branch if unsure 1044 | - Only use `-D` when you're 100% ready 1045 | 1046 | --- 1047 | 1048 | ## 🧠 Git Challenge: Practice Config, Ignore, Stash & Recovery 1049 | 1050 | Try these steps to put everything together: 1051 | 1052 | 1. Create a folder `my-git-tools` 1053 | 2. Open in VSCode, open terminal 1054 | 3. Run: 1055 | 1056 | ```bash 1057 | git init 1058 | ``` 1059 | 1060 | 4. Set local name and email: 1061 | 1062 | ```bash 1063 | git config user.name "Your Local Name" 1064 | git config user.email "your@local.email" 1065 | ``` 1066 | 1067 | 5. Add and commit 3 files (`main-01.txt`, `main-02.txt`, `main-03.txt`) 1068 | 6. Create `.gitignore` with: 1069 | 1070 | ```bash 1071 | temp\*.md 1072 | ``` 1073 | 1074 | 7. Create `.temp-1.md` and `.temp-99.md` 1075 | 8. Run: 1076 | 1077 | ```bash 1078 | git status 1079 | ``` 1080 | 1081 | 9. Modify `main-01.txt` but don't commit 1082 | 10. Stash your changes: 1083 | 1084 | ```bash 1085 | git stash push -m "work in progress" 1086 | ``` 1087 | 1088 | 11. Check stashes: 1089 | 1090 | ```bash 1091 | git stash list 1092 | ``` 1093 | 1094 | 12. Apply the stash: 1095 | 1096 | ```bash 1097 | git stash pop 1098 | ``` 1099 | 1100 | 13. View commit log: 1101 | 1102 | ```bash 1103 | git log --oneline 1104 | ``` 1105 | 1106 | 14. Copy a hash and check it out: 1107 | 1108 | ```bash 1109 | git checkout 1110 | ``` 1111 | 1112 | 15. Make a change and commit 1113 | 16. Realize you're in detached HEAD, save it: 1114 | 1115 | ```bash 1116 | git checkout -b recovery-branch 1117 | ``` 1118 | 1119 | 17. Switch back to `main` 1120 | 1121 | 18. View reflog: 1122 | 1123 | ```bash 1124 | git reflog 1125 | ``` 1126 | 1127 | 19. Make 2 commits 1128 | 1129 | 20. Run: 1130 | 1131 | ```bash 1132 | git reset --soft HEAD~1 1133 | ``` 1134 | 1135 | 21. Edit and re-commit 1136 | 1137 | 22. Run: 1138 | 1139 | ```bash 1140 | git reset --hard HEAD~1 1141 | ``` 1142 | 1143 | 23. Confirm changes are gone 1144 | 1145 | 24. Stage a change, then unstage it: 1146 | 1147 | ```bash 1148 | git restore --staged filename.txt 1149 | ``` 1150 | 1151 | 25. Make more changes, discard them: 1152 | 1153 | ```bash 1154 | git restore . 1155 | ``` 1156 | 1157 | 26. Create `temp.txt` and preview clean: 1158 | 1159 | ```bash 1160 | git clean -dn 1161 | ``` 1162 | 1163 | 27. Delete it: 1164 | 1165 | ```bash 1166 | git clean -df 1167 | ``` 1168 | 1169 | --- 1170 | 1171 | ## ✅ Summary 1172 | 1173 | - Use **local config** when working in different teams/projects 1174 | - Use **.gitignore** to keep sensitive and messy files out of Git 1175 | - Use **stash** to save work temporarily without committing 1176 | - Understand **HEAD** and **reflog** to recover lost work 1177 | - Use **reset, restore, and clean** to undo, fix, or clean things up 1178 | 1179 | These are the everyday tools real developers use to avoid mistakes and recover fast when something goes wrong. 1180 | 1181 | --- 1182 | 1183 | _You're now a Git troubleshooting ninja — stash it, reset it, or reflog your way to safety! 🧙_ 1184 | 1185 | # Git Merge Conflicts, Rebase, Squash, and Cherry-Pick: Explained Simply 1186 | 1187 | As your Git projects grow, you'll start working with multiple branches — and sooner or later, you'll run into **merge conflicts**. Don't panic. Conflicts are normal and fixable. In this guide, we'll explain merge conflicts, how to fix them, and how to work with powerful tools like rebase, squash, and cherry-pick. 1188 | 1189 | --- 1190 | 1191 | ## 💥 What Is a Merge Conflict? 1192 | 1193 | A **merge conflict** happens when Git can't figure out how to combine changes from two branches. This usually occurs when: 1194 | 1195 | - Two branches changed the **same line** in a file 1196 | - One branch **deleted** a file while the other **edited** it 1197 | - A file is **renamed** differently in two branches 1198 | - One branch creates a **file**, the other creates a **folder** with the same name 1199 | - Binary files (like images) are edited differently in each branch 1200 | 1201 | When this happens, Git **pauses** the merge and marks the file as conflicted — waiting for you to fix it. 1202 | 1203 | --- 1204 | 1205 | ## 🔄 Rebase vs Merge: What's the Difference? 1206 | 1207 | Both `git merge` and `git rebase` are ways to combine branches, but they behave differently. 1208 | 1209 | ### 👉 Merge (`git merge main` from `feature` branch) 1210 | 1211 | - Keeps the full branch history 1212 | - Creates a new **merge commit** 1213 | - Keeps the context of both branches 1214 | 1215 | How it works: 1216 | 1217 | 1. Finds the common base commit 1218 | 2. Combines the new changes from both branches 1219 | 3. Creates a merge commit 1220 | 1221 | ### 👉 Rebase (`git rebase main` from `feature` branch) 1222 | 1223 | - Rewrites history 1224 | - No merge commit — creates a **clean, linear** history 1225 | - Moves your changes on top of the other branch 1226 | 1227 | How it works: 1228 | 1229 | 1. Temporarily removes your changes 1230 | 2. Updates your branch to match `main` 1231 | 3. Re-applies your changes one by one 1232 | 1233 | 💡 Use rebase when you want a cleaner history. Use merge when you want to preserve the full story. 1234 | 1235 | --- 1236 | 1237 | ## 🧨 Merge Conflicts During Rebase 1238 | 1239 | Rebase also runs into conflicts — especially if the changes in the base branch touch the same lines you've changed. 1240 | 1241 | What happens: 1242 | 1243 | - Git stops and tells you which files are in conflict 1244 | - You must fix the file(s) 1245 | - Then run: 1246 | 1247 | ```bash 1248 | git add filename.txt 1249 | git rebase --continue 1250 | ``` 1251 | 1252 | You can also cancel a rebase: 1253 | 1254 | ```bash 1255 | git rebase --abort 1256 | ``` 1257 | 1258 | --- 1259 | 1260 | ## 🧺 Squashing Commits 1261 | 1262 | Sometimes you make lots of small commits while working on a feature. Instead of merging all of them into `main`, you can **squash** them into one commit. 1263 | 1264 | ### 1. Squash with merge: 1265 | 1266 | ```bash 1267 | git merge --squash feature 1268 | git commit -m "add full feature in one commit" 1269 | ``` 1270 | 1271 | ### 2. Squash with interactive rebase: 1272 | 1273 | ```bash 1274 | git rebase -i HEAD~n 1275 | ``` 1276 | 1277 | This opens a list of your last `n` commits in a text editor. Change `pick` to `squash` or `s` for the commits you want to combine. 1278 | 1279 | Follow the prompts to write the new, single commit message. 1280 | 1281 | --- 1282 | 1283 | ## 🍒 Cherry-Pick 1284 | 1285 | Cherry-pick means **copying a single commit** from one branch and adding it to another. 1286 | 1287 | This is useful when: 1288 | 1289 | - You want one small change from another branch 1290 | - You don't want to merge the whole branch 1291 | 1292 | ### Steps: 1293 | 1294 | 1. Find the commit hash: 1295 | 1296 | ```bash 1297 | git log --oneline 1298 | ``` 1299 | 1300 | 2. Switch to the target branch: 1301 | 1302 | ```bash 1303 | git checkout cherry-target 1304 | ``` 1305 | 1306 | 3. Apply the commit: 1307 | 1308 | ```bash 1309 | git cherry-pick 1310 | ``` 1311 | 1312 | 4. If there are conflicts, resolve them, then run: 1313 | 1314 | ```bash 1315 | git add . 1316 | git cherry-pick --continue 1317 | ``` 1318 | 1319 | You can cherry-pick multiple commits too: 1320 | 1321 | ```bash 1322 | git cherry-pick a1b2c3..f6g7h8 1323 | ``` 1324 | 1325 | --- 1326 | 1327 | ## 🧠 Git Challenge: Practice Merge Conflicts, Rebase & Cherry-Pick 1328 | 1329 | Try this exercise to put everything together: 1330 | 1331 | ### 🔧 Setup 1332 | 1333 | 1. Create a new folder: `git-merge-rebase-practice` 1334 | 2. Open it in VSCode 1335 | 3. Open the terminal: 1336 | 1337 | ```bash 1338 | View > Terminal 1339 | or Ctrl + ` (Windows/Linux) 1340 | Cmd + ` (Mac) 1341 | ``` 1342 | 1343 | 4. Initialize Git: 1344 | 1345 | ```bash 1346 | git init 1347 | ``` 1348 | 1349 | 5. Create and commit a file: 1350 | 1351 | ```bash 1352 | echo "Hello from main" > main.txt 1353 | git add . 1354 | git commit -m "main.txt initial commit" 1355 | ``` 1356 | 1357 | --- 1358 | 1359 | ### 🔀 Create Conflict 1360 | 1361 | 1. Create a branch and switch to it: 1362 | 1363 | ```bash 1364 | git checkout -b feature 1365 | ``` 1366 | 1367 | 2. Modify `main.txt` (same line), commit: 1368 | 1369 | ```bash 1370 | echo "Feature change" > main.txt 1371 | git add . 1372 | git commit -m "update main.txt in feature" 1373 | ``` 1374 | 1375 | 3. Create another file: 1376 | 1377 | ```bash 1378 | echo "New feature file" > feature-1.txt 1379 | git add . 1380 | git commit -m "add feature-1.txt" 1381 | ``` 1382 | 1383 | 4. Switch back to `main`: 1384 | 1385 | ```bash 1386 | git checkout main 1387 | ``` 1388 | 1389 | 5. Modify the same line in `main.txt` differently, commit: 1390 | 1391 | ```bash 1392 | echo "Main branch change" > main.txt 1393 | git add . 1394 | git commit -m "conflicting change in main" 1395 | ``` 1396 | 1397 | --- 1398 | 1399 | ### ⚔️ Trigger a Merge Conflict 1400 | 1401 | 1. Merge `main` into `feature`: 1402 | 1403 | ```bash 1404 | git checkout feature 1405 | git merge main 1406 | ``` 1407 | 1408 | Git will stop and show a conflict in `main.txt`. 1409 | 1410 | 2. Open `main.txt`, you'll see: 1411 | 1412 | ```bash 1413 | <<<<<<< HEAD 1414 | Feature change 1415 | ======= 1416 | Main branch change 1417 | >>>>>>> main 1418 | ``` 1419 | 1420 | 3. Pick the correct version or combine both. Then save and exit. 1421 | 1422 | 4. Stage the file: 1423 | 1424 | ```bash 1425 | git add main.txt 1426 | ``` 1427 | 1428 | 5. Finish the merge: 1429 | 1430 | ```bash 1431 | git commit 1432 | ``` 1433 | 1434 | --- 1435 | 1436 | ### 🧼 Squash the Commits 1437 | 1438 | 1. Switch to `main`: 1439 | 1440 | ```bash 1441 | git checkout main 1442 | ``` 1443 | 1444 | 2. Squash merge `feature`: 1445 | 1446 | ```bash 1447 | git merge --squash feature 1448 | git commit -m "squashed feature changes" 1449 | ``` 1450 | 1451 | --- 1452 | 1453 | ### 🔁 Practice Rebase 1454 | 1455 | 1. Reset to the commit before merge: 1456 | 1457 | ```bash 1458 | git reset --hard HEAD~1 1459 | ``` 1460 | 1461 | 2. Switch to `feature`, then rebase: 1462 | 1463 | ```bash 1464 | git checkout feature 1465 | git rebase main 1466 | ``` 1467 | 1468 | Resolve the conflict as before. Then run: 1469 | 1470 | ```bash 1471 | git add main.txt 1472 | git rebase --continue 1473 | ``` 1474 | 1475 | --- 1476 | 1477 | ### ✂️ Interactive Rebase 1478 | 1479 | Make a few small commits: 1480 | 1481 | ```bash 1482 | echo "line1" >> notes.txt 1483 | git add . && git commit -m "add line1" 1484 | echo "line2" >> notes.txt 1485 | git add . && git commit -m "add line2" 1486 | ``` 1487 | 1488 | Now run: 1489 | 1490 | ```bash 1491 | git rebase -i HEAD~2 1492 | ``` 1493 | 1494 | Change `pick` to `squash` for the second commit. Save and confirm the new message. 1495 | 1496 | --- 1497 | 1498 | ### 🍒 Cherry-Pick a Commit 1499 | 1500 | 1. Switch to `feature` and make a new change: 1501 | 1502 | ```bash 1503 | echo "unique update" > cherry.txt 1504 | git add . 1505 | git commit -m "special change to cherry-pick" 1506 | ``` 1507 | 1508 | 2. Copy the commit hash: 1509 | 1510 | ```bash 1511 | git log --oneline 1512 | ``` 1513 | 1514 | 3. Switch to `cherry-target`: 1515 | 1516 | ```bash 1517 | git checkout -b cherry-target 1518 | ``` 1519 | 1520 | 4. Cherry-pick the commit: 1521 | 1522 | ```bash 1523 | git cherry-pick 1524 | ``` 1525 | 1526 | --- 1527 | 1528 | ## ✅ Summary 1529 | 1530 | - Conflicts happen when two branches change the same thing. 1531 | - Rebase creates a cleaner history, but merge preserves the original timeline. 1532 | - Squash helps you combine messy commits into one. 1533 | - Cherry-pick lets you copy just one change without merging everything. 1534 | 1535 | With these tools, you're ready to work like a real Git pro — even when things get messy. 1536 | 1537 | --- 1538 | 1539 | _Next time you see conflict markers, don't panic — you're ready to fix them like a boss._ 👨‍💻👩‍💻 1540 | 1541 | # GitHub for Beginners: Remotes, SSH, Pull Requests & Collaboration 1542 | 1543 | You've learned how to use Git locally. Now let's take things to the next level — working with GitHub! GitHub is a platform that helps you **host your code online**, **collaborate with others**, and **track changes** as a team. 1544 | 1545 | --- 1546 | 1547 | ## 🌐 What is GitHub? 1548 | 1549 | GitHub is the world's largest development platform where: 1550 | 1551 | - You can **host your Git repositories** 1552 | - Collaborate with teammates or open-source communities 1553 | - Share code, track issues, and submit pull requests (PRs) 1554 | 1555 | --- 1556 | 1557 | ## 🔗 Working with Remotes 1558 | 1559 | When you connect your local Git project to GitHub, you set up a **remote**. GitHub becomes the online version of your project. 1560 | 1561 | Here are the essential Git remote commands: 1562 | 1563 | ### 1. Add a Remote 1564 | 1565 | ```bash 1566 | git remote add origin https://github.com/username/repo.git 1567 | ``` 1568 | 1569 | - `origin` is a nickname for the remote GitHub repo. 1570 | - The URL is the repo's SSH or HTTPS link. 1571 | 1572 | --- 1573 | 1574 | ### 2. Push Your Changes 1575 | 1576 | ```bash 1577 | git push -u origin main 1578 | ``` 1579 | 1580 | - Sends your local commits to GitHub. 1581 | - Use `-u` to set tracking so future pushes don't need branch names. 1582 | 1583 | For feature branches: 1584 | 1585 | ```bash 1586 | git push -u origin feature-name 1587 | ``` 1588 | 1589 | --- 1590 | 1591 | ### 3. Fetch Updates (No Merge) 1592 | 1593 | ```bash 1594 | git fetch 1595 | ``` 1596 | 1597 | - Downloads new data from GitHub but **does not change** your files. 1598 | - Use when you want to review changes before applying them. 1599 | 1600 | --- 1601 | 1602 | ### 4. Pull Changes (Fetch + Merge) 1603 | 1604 | ```bash 1605 | git pull 1606 | ``` 1607 | 1608 | - Updates your branch with the latest changes from GitHub. 1609 | - Combines `fetch` + `merge`. 1610 | 1611 | --- 1612 | 1613 | ### 5. Clone a Repo 1614 | 1615 | ```bash 1616 | git clone https://github.com/username/repo.git 1617 | ``` 1618 | 1619 | - Makes a local copy of a GitHub repo. 1620 | - Sets up remotes automatically. 1621 | 1622 | --- 1623 | 1624 | ## 🔐 Setting Up SSH with GitHub 1625 | 1626 | Using SSH is a secure and convenient way to connect to GitHub without typing your password every time. 1627 | 1628 | ### Steps: 1629 | 1630 | 1. Check for existing SSH keys: 1631 | 1632 | ```bash 1633 | ls -al ~/.ssh 1634 | ``` 1635 | 1636 | 2. Generate a new SSH key: 1637 | 1638 | ```bash 1639 | ssh-keygen -t ed25519 -C "you@example.com" 1640 | ``` 1641 | 1642 | 3. Copy the public key: 1643 | 1644 | ```bash 1645 | pbcopy < ~/.ssh/id_ed25519.pub 1646 | ``` 1647 | 1648 | 4. Go to GitHub: 1649 | 1650 | - **Settings > SSH and GPG keys > New SSH key** 1651 | - Paste and save 1652 | 1653 | 5. Test connection: 1654 | 1655 | ```bash 1656 | ssh -T git@github.com 1657 | ``` 1658 | 1659 | If you get a success message, you're all set! 1660 | 1661 | --- 1662 | 1663 | ### Optional: SSH Config File 1664 | 1665 | If needed, add a config file: 1666 | 1667 | ```bash 1668 | touch ~/.ssh/config 1669 | ``` 1670 | 1671 | Example config: 1672 | 1673 | ```bash 1674 | Host github.com 1675 | AddKeysToAgent yes 1676 | IdentityFile ~/.ssh/id_ed25519 1677 | ``` 1678 | 1679 | Then run: 1680 | 1681 | ```bash 1682 | ssh-add ~/.ssh/id_ed25519 1683 | ``` 1684 | 1685 | --- 1686 | 1687 | ## 🚀 First GitHub Project 1688 | 1689 | 1. Create a new folder locally and initialize Git: 1690 | 1691 | ```bash 1692 | git init 1693 | ``` 1694 | 1695 | 2. Add a file and commit: 1696 | 1697 | ```bash 1698 | echo "console.log('hello')" > app.js 1699 | git add . 1700 | git commit -m "initial commit" 1701 | ``` 1702 | 1703 | 3. On GitHub, create a new repository. 1704 | 1705 | 4. Connect and push: 1706 | 1707 | ```bash 1708 | git remote add origin git@github.com:username/repo.git 1709 | git branch -M main 1710 | git push -u origin main 1711 | ``` 1712 | 1713 | 5. Make more changes locally and push again: 1714 | 1715 | ```bash 1716 | git add . 1717 | git commit -m "second commit" 1718 | git push 1719 | ``` 1720 | 1721 | --- 1722 | 1723 | ## 🧠 Pull Requests (PRs) 1724 | 1725 | Pull Requests let you share changes with others and ask for review. 1726 | 1727 | 1. Create a new branch: 1728 | 1729 | ```bash 1730 | git checkout -b feature-xyz 1731 | ``` 1732 | 1733 | 2. Make changes and commit. 1734 | 1735 | 3. Push the branch to GitHub: 1736 | 1737 | ```bash 1738 | git push -u origin feature-xyz 1739 | ``` 1740 | 1741 | 4. Go to GitHub, click "Compare & pull request". 1742 | 1743 | 5. Add a description and create the PR. 1744 | 1745 | Now collaborators can review, suggest changes, or approve it for merging. 1746 | 1747 | --- 1748 | 1749 | ## 🧪 Practice PR with TICKET-22 Branch 1750 | 1751 | 1. Create a new branch: 1752 | 1753 | ```bash 1754 | git checkout -b TICKET-22 1755 | ``` 1756 | 1757 | 2. Edit files: 1758 | 1759 | ```bash 1760 | echo "hello people" >> main-01.txt 1761 | echo "hello from ticket-22" > hello.js 1762 | echo "app is running..." > app.js 1763 | ``` 1764 | 1765 | 3. Make 2 commits: 1766 | 1767 | ```bash 1768 | git add . 1769 | git commit -m "TICKET-22 make changes" 1770 | git commit -am "TICKET-22 update app.js" 1771 | ``` 1772 | 1773 | 4. Merge `main` into `TICKET-22`: 1774 | 1775 | ```bash 1776 | git merge main 1777 | ``` 1778 | 1779 | 5. Push to GitHub: 1780 | 1781 | ```bash 1782 | git push -u origin TICKET-22 1783 | ``` 1784 | 1785 | 6. Open a pull request. 1786 | 1787 | --- 1788 | 1789 | ## 💬 What If You See "Already up to date"? 1790 | 1791 | That means the branches don't have new changes to merge. Just continue working or open a PR if your branch is ready to merge. 1792 | 1793 | --- 1794 | 1795 | ## 🔄 Understanding Remotes and Remote-Tracking Branches 1796 | 1797 | ### What is a Remote? 1798 | 1799 | A remote is a version of your project stored online (like GitHub). 1800 | 1801 | ### What is a Remote-Tracking Branch? 1802 | 1803 | When you `fetch`, Git updates your local copy of the remote branch (like `origin/main`). This lets you see what changed without modifying your current branch. 1804 | 1805 | --- 1806 | 1807 | ### Check All Branches (Local + Remote) 1808 | 1809 | ```bash 1810 | git branch -a 1811 | ``` 1812 | 1813 | You'll see something like: 1814 | 1815 | ```bash 1816 | main 1817 | remotes/origin/main 1818 | remotes/origin/TICKET-22 1819 | ``` 1820 | 1821 | --- 1822 | 1823 | ## ⚡ Common Remote Actions 1824 | 1825 | ### Fetch: 1826 | 1827 | ```bash 1828 | git fetch origin 1829 | ``` 1830 | 1831 | - Downloads updates but doesn't merge. 1832 | 1833 | ### Pull: 1834 | 1835 | ```bash 1836 | git pull origin main 1837 | ``` 1838 | 1839 | - Downloads and merges changes into your current branch. 1840 | 1841 | ### Push: 1842 | 1843 | ```bash 1844 | git push origin feature-name 1845 | ``` 1846 | 1847 | - Sends your local commits to GitHub. 1848 | 1849 | --- 1850 | 1851 | ## ✍️ Interactive Rebase and Force Push 1852 | 1853 | Let's say you want to squash commits in your branch: 1854 | 1855 | ```bash 1856 | git rebase -i HEAD~3 1857 | ``` 1858 | 1859 | Mark some commits as `squash`, save, and follow the prompts. 1860 | 1861 | Then push: 1862 | 1863 | ```bash 1864 | git push -f 1865 | ``` 1866 | 1867 | ⚠️ Use force push carefully — it rewrites history and can overwrite others' work if you're sharing the branch. 1868 | 1869 | --- 1870 | 1871 | ## 🍒 Cherry-Picking Commits from Another Branch 1872 | 1873 | Cherry-pick lets you copy a single commit from one branch to another. 1874 | 1875 | ### Steps: 1876 | 1877 | 1. Copy commit hash from `git log` 1878 | 2. Switch to your target branch: 1879 | 1880 | ```bash 1881 | git checkout checkout 1882 | ``` 1883 | 1884 | 3. Cherry-pick the commit: 1885 | 1886 | ```bash 1887 | git cherry-pick 1888 | ``` 1889 | 1890 | If Git can't find the commit: 1891 | 1892 | - Run: 1893 | 1894 | ```bash 1895 | git fetch 1896 | ``` 1897 | 1898 | - Try again 1899 | 1900 | Cherry-pick is useful when you want one feature or fix from another branch without merging the whole thing. 1901 | 1902 | --- 1903 | 1904 | ## 🧠 GitHub Collaboration Challenge 1905 | 1906 | 1. Create a GitHub repo and clone it in 3 folders: `dev1`, `dev2`, `dev3` 1907 | 1908 | ### In `dev1`: 1909 | 1910 | - Create branch `TICKET-11` 1911 | - Change `app.js`, commit 1912 | - Merge `main` into it 1913 | - Push to GitHub 1914 | - Create PR → Merge using **merge** 1915 | 1916 | ### In `dev2`: 1917 | 1918 | - Create branch `TICKET-22` 1919 | - Make 2 commits to `app.js` 1920 | - Push to GitHub 1921 | - Create PR → Merge using **merge** 1922 | 1923 | ### In `dev3`: 1924 | 1925 | - Create branch `TICKET-33` 1926 | - Make 3 commits 1927 | - Use interactive rebase to squash 1928 | - Rebase onto `main` 1929 | - Force push to GitHub 1930 | - Create PR → Merge using **rebase** 1931 | 1932 | --- 1933 | 1934 | ## 🍒 Advanced Cherry-Pick Practice 1935 | 1936 | 1. Clone the repo into `dev4` and `dev5` 1937 | 1938 | ### In `dev4`: 1939 | 1940 | - Create branch `feature` 1941 | - Add `feature.txt` 1942 | - Commit and push 1943 | 1944 | ### In `dev5`: 1945 | 1946 | - Create branch `checkout` 1947 | - Add `checkout.txt` 1948 | - Commit 1949 | 1950 | Try to cherry-pick `feature.txt` commit → you'll get an error 1951 | 1952 | Fix it with: 1953 | 1954 | ```bash 1955 | git fetch 1956 | ``` 1957 | 1958 | Then: 1959 | 1960 | ```bash 1961 | git cherry-pick 1962 | ``` 1963 | 1964 | Now the commit can be applied. 1965 | 1966 | --- 1967 | 1968 | ## ✅ Summary 1969 | 1970 | - Use `git remote` and `push/pull/fetch/clone` to connect local and remote repos 1971 | - Use SSH for secure communication with GitHub 1972 | - Use branches + PRs for team collaboration 1973 | - Use `rebase` to clean up commit history 1974 | - Use `cherry-pick` to bring over specific changes 1975 | - Use force-push only when you know what you're doing 1976 | 1977 | --- 1978 | 1979 | _You're now ready to work with teams, contribute to open source, and push your projects to the world with GitHub!_ 🚀 1980 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Practical Git and Github : From Basics to Pro Workflows 2 | 3 | ## What is Git? 4 | 5 | - version control 6 | - manage code history 7 | - track changes 8 | 9 | ## 📦 Git Installation and Configuration Essentials 10 | 11 | When you install Git for the first time, it's important to configure your **username** and **email address**. These settings are attached to every commit you make and help identify the author of the code changes. 12 | **Essential Git Config Commands** 13 | 14 | Run these in your terminal or Git Bash: 15 | 16 | ```sh 17 | git config --global user.name "Your Name" 18 | git config --global user.email "your.email@example.com" 19 | ``` 20 | 21 | - `--global`: Applies the settings to all Git projects on your system. 22 | - there is aso a `--local` option that applies the settings to the current project only which we will cover later 23 | - To set a different name/email for a specific project, remove `--global` and run the command inside that project folder. 24 | 25 | **Why This Is Important** 26 | 27 | - Commit Attribution: Each commit is tagged with your name and email. 28 | - Collaboration: Platforms like GitHub use this information to track contributions. 29 | - Verification: GitHub can verify commits based on your email. 30 | 31 | To view your current global settings: 32 | 33 | ```sh 34 | git config --global --list 35 | ``` 36 | 37 | To view all settings and their origin: 38 | 39 | ```sh 40 | git config --list --show-origin 41 | ``` 42 | 43 | ## 🚀 Common Git Commands (Quick Reference) 44 | 45 | `git init` 46 | 47 | Initializes a new Git repository in your current directory. 48 | Creates a hidden `.git/` folder to start tracking changes,and that's how you know it's a git repo. 49 | 50 | `cd .git` and `ls` - will show you the contents of the .git directory. This is where git stores all the information about the repo, or `find .git`. 51 | 52 | `git status` - will show you the current state of your working directory and staging area, including what's staged, what's modified, and what's untracked. 53 | 54 | `git add` 55 | 56 | Adds files to the staging area (prepares them for commit). 57 | 58 | - Add one file: `git add fileName.txt` 59 | - Add all files: `git add .` or `git add -A` (subtle differences exist between these, will explain later) 60 | 61 | later 62 | 63 | `git commit -m "your message"` 64 | 65 | Saves your staged changes to the repository with a message describing the update. 66 | Best practices for commit messages: 67 | 68 | - ✅ Use the imperative mood (like a command) 69 | - ✅ Use the present tense 70 | - ✅ This commit will "do this" 71 | 72 | Examples: 73 | 74 | ```sh 75 | git commit -m "add login validation" 76 | git commit -m "create navbar layout" 77 | ``` 78 | 79 | ````sh 80 | 81 | - ❌ Avoid vague messages: 82 | 83 | ```sh 84 | git commit -m "stuff" 85 | git commit -m "update" 86 | ```` 87 | 88 | 💡 Remember, commit messages are like a diary for your code. They help you and others understand the history of changes and they publicly visible on platforms like GitHub 😀 89 | 90 | `git status` 91 | 92 | Shows the current state of your working directory and staging area. 93 | 94 | - What's staged 95 | - What's modified 96 | - What's untracked 97 | 98 | `git log` 99 | 100 | Shows the commit history (latest first). 101 | 102 | - Includes commit hash, author, date, and message 103 | - Hash: The hash is a unique identifier for each commit, allowing you to reference or revert to specific changes. 104 | - Press `q` to exit the log view 105 | 106 | `git log --oneline` 107 | 108 | Shows the commit history in a simplified, one-line-per-commit format. 109 | 110 | 💡 Tracking 111 | 112 | - before we add file to the staging area, it's in the "untracked" state 113 | - after we add it to the staging area, it's in the "staged" state 114 | - after we commit it, it's in the "tracked" state 115 | - after we modify it, it's in the "modified" state 116 | 117 | It will become important once you want to reset or revert changes. 118 | If you delete the file while it's still untracked, it will be lost forever. 119 | 120 | ## First Git Project 121 | 122 | For all of the "terminal command enthusiasts," I think you will find this useful 👇👇👇 😀😀😀 123 | 124 | `echo "file-02.md" > file-02.md` - will create a new file called file-02.md and write the text "file-02.md" into it. The > operator is used to redirect the output of the echo command into the file. If the file already exists, this command will overwrite its contents. If you want to append to the file instead of overwriting it, you can use the >> operator. 125 | 126 | **Practice Exercise** 127 | 128 | - create a new folder `git-tutorial` 129 | - open the folder in VSCode 130 | - open the terminal in VSCode "View > Terminal" or "Ctrl + `" 131 | - run `ls -la` to see hidden files (like `.git`) 132 | - since this is a new folder, you won't see any hidden files 133 | - run `git status` to see the current state of your project 134 | - since this is not a Git repository yet, you will see an error message 135 | - run `git init` to initialize a new Git repository 136 | - run `git status` again to see the current state of your project 137 | - create file `main-01.txt` and add some text to it 138 | - run `git status` again to see the current state of your project 139 | - run `git add main-01.txt` to stage the file 140 | - run `git status` again to see the current state of your project 141 | - run `git commit -m "add main-01.txt"` to commit the staged file 142 | - run `git status` again to see the current state of your project 143 | - run `git log` to see the commit history 144 | - create files `main-02.txt` and `main-03.txt` and add some text to it 145 | - run `git add .` to stage all files 146 | - run `git status` again to see the current state of your project 147 | - run `git commit -m "add main-02.txt and main-03.txt"` to commit the staged files 148 | - run `git log --online` to see the commit history 149 | - repeat the process one more time to add a new file `main-04.txt` and commit it 150 | - run `git log --oneline` to see the commit history 151 | 152 | ## Modify a File 153 | 154 | - open `main-04.txt` and change the text 155 | - create a new folder `colors` 156 | - create a new file `red.txt` inside the `colors` folder 157 | - add some text to `red.txt` 158 | - run `git status` to see the current state of your project 159 | - run `git add .` to stage all files 160 | - run `git status` again to see the current state of your project 161 | - run `git commit -m "add red.txt and modify main-04.txt"` to commit the staged files 162 | - run `git log --oneline` to see the commit history 163 | 164 | ## VSCode Git Integration 165 | 166 | - create a new folder `vscode-git` 167 | - open the folder in VSCode 168 | - repeat the steps but with VSCode GUI 169 | 170 | ## Navigating Commits with Hashes 171 | 172 | - Run `git log --oneline` to see all commits. 173 | 174 | - Copy the hash you want. 175 | - Run `git checkout ` to go there. 176 | - You've time-traveled to that snapshot 😀 177 | - Run `git log --oneline` to see fewer commits. 178 | - Don't change files (detached HEAD). 179 | - Will cover 'detached HEAD' later. 180 | - Run `git checkout main` (or `master`) to return. 181 | - Will discuss branches next. 182 | - repeat steps with `VSCode GUI` 183 | 184 | ## ⚠️ Git Command Nuances and Repository Safety 185 | 186 | **`git add .` vs `git add -A`** 187 | 188 | - `git add .` adds all changes in the current directory and its subdirectories. 189 | - `git add -A` adds all changes in the entire repository, regardless of your current directory. 190 | 191 | **Demo:** 192 | 193 | - create a new folder `big-project` 194 | - create two folders `front-end` and `server` 195 | - create `index.html` and `main.css` inside the `front-end` folder (add some code to them) 196 | - in the `server` folder, create `app.js` and add console.log("Hello from server") to it 197 | - run `git init` to initialize a new Git repository 198 | - navigate to server folder and run `node app.js` to see the output 199 | - run `git add .` to stage all files 200 | - notice that `git add .` only stages the files in the current directory and its subdirectories 201 | - notice that `git add -A` stages all files in the entire repository 202 | - notice that VSCode GUI allows you to stage all files in the entire repository 203 | 204 | ### Protecting Your .git Directory 205 | 206 | ⚠️ The `.git` directory contains Git's internal database and configuration files. You should **never**: 207 | 208 | - create subdirectories inside the `.git` directory 209 | - manually modify the contents of the `.git` directory 210 | - initialize a Git repository inside another repository's `.git` directory 211 | 212 | **Why this is dangerous:** 213 | 214 | - it can corrupt your Git repository 215 | - it may cause Git commands to fail or behave unpredictably 216 | - it can lead to loss of commit history 217 | - it breaks Git's internal structure and references 218 | 219 | **⚠️ BAD EXAMPLES — NEVER DO THIS IN REAL PROJECTS! ⚠️** 220 | **⚠️ DEMO PURPOSES ONLY ⚠️** 221 | 222 | - navigate to `front-end` folder and run `git init` to initialize a new Git repository inside an existing repository 223 | - run `cd .git` followed by `git init` to initialize a new Git repository inside the `.git` directory 224 | 225 | Next, we'll cover branches, merging, and rebasing. For now, we'll stick to the "happy path" — a smooth workflow without errors or conflicts. Don't worry, we'll dive into handling those issues later. 226 | 227 | ## 🧠 Git Challenge: First Project 228 | 229 | - Create a new folder called `my-git-project` 230 | - Open the folder in VSCode 231 | - Open the terminal in VSCode (`View > Terminal` or `Ctrl + ``) 232 | - Look for hidden files (you shouldn't see any at this point) 233 | - Check the current Git status — you'll likely get an error 234 | - Turn this folder into a Git repository 235 | - Check the Git status again — notice the difference 236 | - Create a file `main.txt` and write some content inside 237 | - Check the Git status — see which state the file is in 238 | - Stage the file for commit 239 | - Commit the file with a descriptive message 240 | - Review the commit history in a simplified format 241 | - Modify the content of `main.txt` 242 | - Create a folder named `notes` and a file `notes/todo.txt` with some text 243 | - Stage all current changes 244 | - Commit again with a clear message 245 | - Review the commit history in a simplified format 246 | 247 | ## Branches 248 | 249 | - `git branch` — List all branches. 250 | - `git branch ` — Create a new branch. 251 | - `git checkout ` — Switch to a branch. 252 | - `git switch ` — Switch to a branch (since Git 2.23). 253 | - `git checkout -b ` — Create and switch to a new branch. 254 | - `git switch -c ` — Create and switch to a new branch (since Git 2.23). 255 | 256 | ## Example: Working with Branches 257 | 258 | - Create a new project `git-branches` 259 | - Initialize Git. 260 | - Create `main-01.txt`. 261 | - Add `main-01.txt` to the staging area and commit. 262 | - Repeat the steps for `main-02.txt`. 263 | - Create a new branch called "feature": `git branch feature` 264 | - Switch to the "feature" branch: `git checkout feature` 265 | - Run `git branch` to see the current branch. 266 | - Create a new file `features/feature-01.txt`. 267 | - Add `features/feature-01.txt` to the staging area and commit. 268 | - Switch back to the "main" branch: `git checkout main` 269 | - Notice that `feature-01.txt` is not present in the "main" branch. 270 | - Each branch can have its own set of files and changes, so switching branches can feel like switching between different versions of your project. 271 | 272 | ## Practice: Creating and Using a New Branch with a Shortcut 273 | 274 | - Open the terminal and run: `git checkout -b bugfix` to create and switch to the `bugfix` branch. 275 | - Create a new file called `bugfix/file-01.txt` and add some text. 276 | - Stage and commit `bugfix/file-01.txt`. 277 | - Switch back to the `main` branch. 278 | - Notice that `file-01.txt` is not present in the `main` branch. 279 | - Each branch can have its own files and changes, so switching branches lets you work on different features or versions independently. 280 | 281 | ## Merging Branches 282 | 283 | Merging combines changes from one branch into another, allowing you to bring together different lines of development. There are two types of merges: 284 | 285 | - **Fast-Forward (FF)**: Happens when the target branch has no new commits since the source branch diverged. Git simply moves the target branch pointer forward to the source branch's latest commit, creating a linear history. 286 | 287 | - **Three-Way Merge**: Occurs when both branches have new commits. Git creates a new merge commit that combines the changes from both branches, preserving the divergent history. 288 | 289 | - The main command is: `git merge ` 290 | - To merge the `main` branch into your current branch (e.g., `feature`): 291 | `git merge main` 292 | - Since main has no new changes, we are already up to date and the merge will be a fast-forward (no merge commit needed). 293 | - To merge your feature branch back into `main`: 294 | - Switch to `main`: `git checkout/switch main` 295 | - Run `git branch` to verify that we are on `main` 296 | - Run `git merge feature` 297 | - Run `git log --oneline` 298 | - Notice `(HEAD -> main, feature)` 299 | 300 | When both branches point to the same commit, HEAD points to the branch you have checked out (e.g., main), and both branches reference the same spot in the commit history. This happens because no new commits have been made on either branch since they were last synchronized. 301 | 302 | - To merge the `main` branch into `bugfix`: 303 | - Switch to `bugfix`: `git checkout/switch bugfix` 304 | - Since we just merged `feature` into `main`, main has new changes, so the branches have diverged, which means it won't be a fast-forward merge. 305 | - Run `git merge main` 306 | - Provide a commit message for the merge commit. 307 | - Run `git log --oneline` to see the commit history. 308 | - Switch back to `main`: `git checkout/switch main` 309 | - Run `git merge bugfix` to merge the `bugfix` branch into `main`. 310 | - Run `git log --oneline` to see the commit history. 311 | - Run `git status` to check the current state of the repository. 312 | 313 | **How to Edit the Merge Commit Message:** 314 | 315 | **1. In VSCode GUI:** 316 | 317 | - The commit message will appear in the Source Control panel at the top. 318 | - Click into the message box, edit the text as you like, and then click the **"Continue"** or **"Commit"** button to finish the merge. 319 | 320 | **2. In the Terminal Editor (like Vim or Nano):** 321 | 322 | - If Git opens a terminal editor (like Vim), you can edit the message directly in the editor window. 323 | 324 | **For Vim:** 325 | 326 | - Press `i` to enter insert mode. 327 | - Edit the message as you wish. 328 | - Press `Esc` to exit insert mode. 329 | - Type `:wq` and press `Enter` to save and quit. 330 | 331 | **For Nano:** 332 | 333 | - Edit the message as you wish. 334 | - Press `Ctrl+O` to save, then `Enter`. 335 | - Press `Ctrl+X` to exit. 336 | 337 | ## Deleting Branches 338 | 339 | To delete a branch, you can use the `git branch -d ` command. This will delete the specified branch if it has been fully merged into your current branch. If the branch has not been merged, Git will prevent the deletion to avoid losing unmerged changes. 340 | 341 | - To delete the `feature` branch, first switch to the `main` branch: `git checkout main` 342 | - Then run `git branch -d feature` to delete the `feature` branch. 343 | - Repeat the process for the `bugfix` branch. 344 | - Create a new branch called `test`, create a new file `test.txt`, and add some text to it. 345 | - Stage and commit `test.txt`. 346 | - Switch to the `main` branch and run `git branch -d test` to delete the `test` branch. 347 | - Since the `test` branch has unmerged changes, Git will prevent the deletion. 348 | - To force delete the `test` branch, run `git branch -D test`. 349 | - Run `git branch` to see the current branches. 350 | 351 | **Why merge into the feature branch first?** 352 | Merging `main` into your feature branch lets you update your feature with the latest changes from `main` and resolve any conflicts early. This makes the final merge back into `main` smoother and helps prevent surprises or conflicts later. 353 | 354 | ## Rebase 355 | 356 | Rebase rewrites commit history by moving a branch's commits onto a new base, creating new commits with different hashes. It results in a cleaner, linear history but should be used carefully, especially on shared branches, to avoid conflicts and confusion. 357 | 358 | ⛔️ Don't use rebase on public branches, as it rewrites commit history and can cause confusion for collaborators. In our case, it's the main branch, so we won't use rebase here, since we would not do that in production. 359 | 360 | Repeat the steps above but with rebasing instead of merging. 361 | 362 | - so in both cases, when we merge `main` into `feature` and `bugfix`, we will use rebase instead of merge. 363 | - create new project `git-rebase` 364 | - initialize Git repository: `git init` 365 | - rest of the steps are the same as above 366 | - compare VSCode GUI for `git-branches` and `git-rebase` 367 | - notice that the commit history is different 368 | 369 | While working on personal projects, the choice is entirely up to you; however, for work projects, team standards are typically followed. For example, in my case, we are required to use rebase, so it's important to understand both merging and rebasing. 370 | 371 | ## Using VSCode's Git Interface 372 | 373 | Repeat the steps above using the VSCode GUI. You can use the Source Control panel to create branches and merge changes without needing to type commands in the terminal. 374 | 375 | 💡 When you use the merge option in the VSCode Source Control GUI, it often auto-generates and auto-commits the default merge message for you, so you don't have to manually confirm or edit it. This makes the process faster and more user-friendly. 376 | 377 | ## 🧠 Git Challenge: Branching & Merging 378 | 379 | - Create a new folder called `my-branch-project` 380 | - Open the folder in VSCode 381 | - Open the terminal in VSCode (`View > Terminal` or `Ctrl + ``) 382 | - Initialize a Git repository 383 | - Create a file `main-01.txt`, add some text, stage, and commit it 384 | - Create another file `main-02.txt`, add content, stage, and commit again 385 | - Create two branches `feature` and `bugfix` 386 | - Switch to `main` and create another file `main-02.txt`, add content, stage, and commit again 387 | - Switch to `feature` branch 388 | - In the `feature` branch, create a file `features/feature-01.txt`, add content, stage, and commit 389 | - Switch back to the `main` branch — notice the `feature-01.txt` file is not there 390 | - Switch back to `feature` 391 | - Merge the `main` branch into `feature` 392 | - Merge the `feature` branch into `main` 393 | - Review the commit history in a simplified format 394 | - Switch to `bugfix` branch 395 | - In the `bugfix` branch, create a file `server/bugfix-01.txt`, add content, stage, and commit 396 | - Repeat the same steps for `server/bugfix-02.txt` 397 | - Rebase `bugfix` onto main 398 | - Merge `bugfix` back into `main` 399 | - Check the commit history again 400 | - Try deleting the `feature` and `bugfix` branches from the `main` branch 401 | - Create a new branch `test`, add a file `test.txt`, and commit it 402 | - Switch to `main` and try to delete the `test` branch — you should see a warning 403 | - Force-delete the `test` branch 404 | 405 | ## Git Config 406 | 407 | Global Git configuration is useful because it sets up your default identity (name and email) for all Git projects on your computer, allowing you to configure these settings once and have them apply everywhere. This is perfect for personal settings that should remain consistent across all your projects. On the other hand, local Git configuration is valuable because it lets you override global settings for specific projects, giving you the flexibility to use different settings (like different email addresses) for different projects. Local settings take priority over global ones, making it ideal for project-specific configurations that shouldn't apply to other repositories. 408 | 409 | The local config file is located in the `.git/config` directory of your repository. This file contains settings that are specific to that repository and override the global settings. 410 | You can view the local config file by running `git config --local --list` or by opening the `.git/config` file in a text editor. 411 | It works the same for the global 412 | 413 | `git config --local --add user.name "shakeAndBake"` 414 | 415 | - `git config --local --add user.name "Your Name"` - Adds a new user.name setting to the local repository configuration, allowing multiple values for the same setting. 416 | 417 | - `git config --local --unset user.name` - Removes the user.name setting from the local repository configuration. 418 | 419 | - `git config --global --unset-all user.name` - Removes all user.name settings from the global Git configuration. 420 | 421 | In Git, you can customize the default branch name used when initializing a new repository by setting the init.defaultBranch configuration. While main is the current standard and master was the legacy default, you can choose any name you like — even something fun like shakeAndBake. To set this globally, run git config `--global init.defaultBranch shakeAndBake`, and Git will use that as the initial branch name in all newly created repositories. This flexibility is especially useful for aligning with team conventions or personal preferences. 422 | 423 | ## .gitignore 424 | 425 | `.gitignore` is a special file in Git that specifies which files and directories should be ignored by Git. When you list files or patterns in .gitignore, Git will not track changes to those files, even if they exist in your working directory. This is particularly useful for excluding temporary files, build outputs, environment-specific configurations, and sensitive information from being committed to your repository. 426 | 427 | **Practice Exercise** 428 | 429 | - Create a new project directory 430 | - Initialize a new Git repository (`git init`) 431 | - Create a file named `main-01.txt` 432 | - Stage and commit the file (`git add main-01.txt` && `git commit -m "initial commit"`) 433 | - Create a `.gitignore` file 434 | - Add `.env` to the `.gitignore` file 435 | - Create a `.env` file in your project, add some sensitive information (e.g., SECRET_KEY="mysecret") 436 | - Notice that Git doesn't track the `.env` file (verify with `git status`) 437 | 438 | ## Git Stash 439 | 440 | - `git stash` - Temporarily saves your uncommitted changes and reverts your working directory to the last commit. This command only works for tracked files and requires at least one commit in the repository. 441 | 442 | - `git stash list` - Shows all stashed changes with their unique identifiers (stash@{0}, stash@{1}, etc.) 443 | - `git stash pop` - Applies the most recent stash and removes it from the stash list 444 | - `git stash apply` - Applies the most recent stash while keeping it in the stash list 445 | - `git stash push -m "message"` - Creates a new stash with a descriptive message to help identify its contents 446 | - `git stash pop stash@{n}` - Applies the specified stash and removes it from the stash list 447 | `git stash` is a command that temporarily saves your uncommitted changes in a "stash" so you can work on something else without losing your progress. It's useful when you need to switch branches or pull changes from a remote repository but don't want to commit your current work yet. 448 | When you run `git stash`, Git takes your uncommitted changes (both staged and unstaged) and saves them in a special stash area. This allows you to revert your working directory to the last commit, making it clean and ready for other tasks. 449 | You can later apply the stashed changes back to your working directory using `git stash apply` or `git stash pop`. The difference is that `git stash pop` removes the stash after applying it, while `git stash apply` keeps the stash for future use. 450 | You can also view your stashes with `git stash list`, which shows a list of all stashed changes. Each stash is identified by a unique name, like `stash@{0}`, `stash@{1}`, etc. You can apply or drop specific stashes using their names. 451 | 452 | **Practice Exercise** 453 | 454 | TODO: 455 | 456 | ## HEAD and Detached HEAD 457 | 458 | **HEAD** 459 | 460 | HEAD in Git is a special pointer that represents your current position in the repository's history. It typically points to the tip of the current branch you're working on, indicating which commit you're currently viewing or working with. When you make new commits, HEAD moves forward with your branch, keeping track of your latest work. Think of it as your current "view" of the repository. 461 | 462 | **detached HEAD** 463 | 464 | A detached HEAD occurs when HEAD points directly to a commit instead of a branch. This happens when you check out a specific commit, tag, or remote branch. In this state, any new commits you make won't be associated with any branch, creating what's called "orphaned" commits. While you can still make changes and commit them in a detached HEAD state, these commits can be lost if you switch branches without creating a new branch to save them. 465 | 466 | **Working with Detached HEAD** 467 | 468 | When you checkout a specific commit using `git checkout `, you enter a detached HEAD state where your HEAD points directly to a commit instead of a branch. In this state, any changes you make and commit create new commits that aren't associated with any branch. These commits become "orphaned" and may be lost when you switch branches (they'll eventually be removed during Git's garbage collection). 469 | To preserve work done in a detached HEAD state, you have several options: 470 | 471 | - Create a new branch from the detached HEAD state using `git checkout -b `. This will save your changes and allow you to continue working on them. 472 | - If you already switch to another branch, you can use `git checkout -b commitHash` to create a new branch from the commit you were working on. 473 | 474 | You can avoid entering a detached HEAD state by always checking out branches instead of specific commits. `git checkout -b branch-name commitHash` creates a new branch from the specified commit, allowing you to work on it without detaching HEAD. This way, you can make changes and commit them to the new branch, keeping your work organized and preventing orphaned commits. 475 | 476 | 💡 If you need to view a specific commit, consider using `git log` or `git show ` (exit with q) instead of checking it out directly. This way, you can explore the commit history without affecting your current branch or creating orphaned commits. 477 | 478 | ## Using `git reflog` 479 | 480 | `git reflog` is a command that allows you to view the reference log of your Git repository. The reference log is a record of all the changes made to the HEAD pointer, including commits, checkouts, merges, and other operations. It provides a way to recover lost commits or branches by showing you the history of where HEAD has pointed in the past. 481 | `git reflog` is particularly useful when you accidentally delete a branch or commit, or when you want to find the commit hash of a previous state in your repository. The reflog is stored in the `.git/logs` directory and is automatically updated by Git whenever you make a change to the repository.` 482 | 483 | The key differences between `git reflog` and `git log` are: 484 | 485 | 1. `git log` shows your formal commit history, displaying the commit hash and message for each commit in your current branch's history. 486 | 487 | 2. `git reflog` shows a complete history of all HEAD movements, including: 488 | - Commits 489 | - Checkouts 490 | - Merges 491 | - Resets 492 | - Rebases 493 | - Branch deletions 494 | - Any other operations that change where HEAD points 495 | 496 | Think of `git log` as your official commit history, while `git reflog` is like a detailed activity log that records every movement of HEAD, making it particularly useful for recovering lost commits or branches after operations like hard resets or branch deletions. 497 | 498 | ## Git Reset 499 | 500 | Git reset is a powerful command that allows you to undo changes in your Git repository. It can be used to unstage files, discard changes, or even remove commits from your history.We will only cover the most common use cases of `git reset` here, since I don't want to overwhelm you with too much information at once. The most common use cases are: 501 | 502 | - `git reset --soft HEAD~1` - undo the last commit but keep the changes staged 503 | - `git reset --hard HEAD~1` - undo the last commit and discard all changes 504 | - `git reset --hard commitHash` - undo all changes and reset to a specific commit 505 | - `git reset` - Unstages changes by moving them from the staging area back to the working directory. 506 | 507 | 💡 In this case, HEAD~1 refers to the commit history from git log, not the reference log from git reflog. 508 | 509 | **Soft Reset** 510 | 511 | The `git reset --soft HEAD~1` command is used to undo the last commit while keeping all the changes staged. The `--soft` flag means that Git will move the HEAD pointer back one commit (`HEAD~1`), but it will keep all the changes from that commit in the staging area. This is useful when you want to: 512 | 513 | - Modify the commit message 514 | - Add more files to the commit 515 | - Split a commit into multiple smaller commits 516 | - Combine the changes with other staged changes before making a new commit 517 | 518 | If you use `HEAD~2` instead of `HEAD~1`, Git will move back two commits and keep all changes from both commits in the staging area. This allows you to combine the last two commits into one or modify them together. Unlike a hard reset, a soft reset is safe as it preserves all your changes in the staging area, allowing you to make a new commit with the same changes. 519 | 520 | ## Hard Reset 521 | 522 | The `git reset --hard HEAD~1` command is a powerful and potentially dangerous command that completely removes the last commit and all its changes. The `--hard` flag tells Git to: 523 | 524 | 1. Move the HEAD pointer back one commit (`HEAD~1`) 525 | 2. Reset the staging area to match the previous commit 526 | 3. Reset the working directory to match the previous commit 527 | 528 | If you use `HEAD~2` instead of `HEAD~1`, Git will move back two commits and permanently remove both the last commit and the one before it, along with all their changes. This means all changes from the last two commits will be permanently lost. Use this command with extreme caution, as there's no way to recover the changes once they're discarded. It's recommended to create a backup branch or stash your changes before using a hard reset if you're unsure about the consequences. 529 | 530 | ## Undoing Staged Changes 531 | 532 | To unstage changes that have been added to the staging area, you have several options. The most common way is to use `git reset filename` to unstage a specific file, or `git reset .` to unstage all files. Alternatively, you can use the newer `git restore --staged filename` command to unstage a specific file, or `git restore --staged .` to unstage all files. Both methods will move the changes from the staging area back to the working directory. If you want to completely discard the staged changes, first unstage them using one of the above commands, then use either `git checkout -- filename` or `git restore filename` to discard changes in a specific file, or `git checkout .` or `git restore .` to discard all changes in the working directory. 533 | 534 | ## Reverting Unstaged Changes 535 | 536 | To discard changes in your working directory, you can use `git checkout`. Running `git checkout .` will revert all unstaged changes in the current directory and its subdirectories. To revert changes in a specific file, use `git checkout -- filename`. This command will restore the file to its state in the last commit, effectively discarding any unstaged changes you've made to that file. 537 | 538 | Alternatively, you can use the newer `git restore` command, which was introduced in Git 2.23 as a more intuitive alternative to `git checkout`. To discard all unstaged changes, use `git restore .`, and to discard changes in a specific file, use `git restore filename`. The `git restore` command is considered more explicit in its purpose and is the recommended way to revert changes in newer versions of Git. 539 | 540 | ## Cleaning Untracked Files 541 | 542 | To remove untracked files from your working directory, you can use `git clean`. The `git clean -dn` command shows a dry-run of what files would be removed without actually deleting them, which is useful for safety checks. To actually remove the untracked files, use `git clean -df`. The `-d` flag includes directories, and the `-f` flag forces the removal. Be cautious with these commands as they permanently delete files that aren't tracked by Git, and the changes cannot be undone. 543 | 544 | ## Deleting Unmerged Branches 545 | 546 | When you delete a branch that has unmerged commits (commits that exist only in that branch and haven't been merged into another branch), Git will warn you and prevent the deletion by default. This is a safety feature to prevent accidental loss of work. To force delete an unmerged branch, you need to use the `-D` flag instead of `-d` (`git branch -D branch_name`). 547 | 548 | However, even after deleting the branch, the commits still exist in Git's object database until they are garbage collected. You can recover a deleted branch if you know its last commit hash. To permanently remove the commits, you would need to use commands like `git gc` or wait for Git's automatic garbage collection to run. 549 | 550 | When you delete a branch that has uncommitted changes (either staged or unstaged), Git will allow the deletion, but the changes will remain in your working directory and staging area, now associated with your main/master branch. At this point, you need to decide what to do with these changes: 551 | 552 | 1. Commit the changes to main/master if they're meant to be there 553 | 2. Stash the changes using `git stash` if you want to save them for later 554 | 3. Discard the changes using `git reset . ` or `git checkout .` if they're no longer needed, or if the files are untracked follow the steps discussed above 555 | 556 | It's generally recommended to: 557 | 558 | 1. Merge important changes before deleting a branch 559 | 2. Create a backup branch if you're unsure about deleting 560 | 3. Use `git branch -d` first to see if there are any unmerged changes 561 | 4. Only use `-D` when you're absolutely sure you want to delete the unmerged commits 562 | 5. Be aware that uncommitted changes will stay in your working directory after branch deletion 563 | 564 | ## 🧠 Git Challenge: Config, Ignore, Stash & Recovery 565 | 566 | - Create a new folder called `my-git-tools` 567 | - Open the folder in VSCode 568 | - Open the terminal in VSCode (`View > Terminal` or `Ctrl + ``) 569 | - Initialize a Git repository 570 | - Set your name and email locally for this specific project 571 | - In three separate commits, create files ,`main-01.txt`,`main-02.txt`,`main-03.txt` add content, stage, and commit it 572 | - Create a `.gitignore` file and add all markdown files that start with `temp` to it 573 | - Create files `.temp-1.md` and `.temp-99.md`, and write some content 574 | - Check the Git status to confirm files are ignored 575 | - Modify `main-01.txt` without committing the change 576 | - Stash the change with a short message 577 | - Check the list of stashes 578 | - Apply the stash and remove it from the stash list 579 | - Confirm that your changes are restored 580 | - View the commit log and copy a random commit hash 581 | - Checkout that commit directly (entering a detached HEAD state) 582 | - Make a change to `main-01.txt` and commit it 583 | - Realize you're not on a branch — create a new branch from this state to save your work 584 | - Switch back to the main branch 585 | - Use reflog to view your recent HEAD movements 586 | - Make two more commits to `main-01.txt` 587 | - Use a soft reset to undo the last commit but keep the changes staged 588 | - Amend the content and recommit with a new message 589 | - Use a hard reset to go back one more commit and fully discard changes 590 | - Confirm that changes are gone 591 | - Stage a new change to `main-01.txt` 592 | - Unstage it using a command of your choice 593 | - Make additional changes and discard them completely (unstaged) 594 | - Create a file `temp.txt` (don't stage or commit it) 595 | - Use a dry-run command to preview what untracked files would be deleted 596 | - Then, permanently remove the untracked file 597 | 598 | -`temp*.md` 599 | 600 | - `**/node_modules` 601 | 602 | ## Merge Conflicts 603 | 604 | A merge conflict occurs when Git cannot automatically resolve differences between two branches during a merge operation. This typically happens when two branches have made changes to the same line of code or when one branch has deleted a file that another branch has modified. When a merge conflict occurs, Git will pause the merge process and mark the conflicting files, allowing you to manually resolve the conflicts before completing the merge. 605 | 606 | **Major Types of Merge Conflicts** 607 | 608 | 1. **Content Conflict**: Occurs when two branches modify the same line in a file differently, or when one branch modifies a line that the other branch deletes. 609 | 610 | 2. **File Add/Delete Conflict**: Happens when one branch deletes a file while the other branch modifies it. 611 | 612 | 3. **File Rename Conflict**: Arises when a file is renamed differently in two branches. 613 | 614 | 4. **Directory/File Conflict**: Occurs when one branch creates a file and the other branch creates a directory with the same name. 615 | 616 | 5. **Binary File Conflict**: Happens when two branches modify a binary file differently, and Git cannot automatically merge the changes. 617 | 618 | ## 🔄 Git Rebase vs Git Merge (Behind the Scenes) 619 | 620 | **👉 `git rebase main` (from `feature-branch`)** 621 | 622 | 1. Git finds your unique commits (not in `main`). 623 | 2. Temporarily saves them (like a patch). 624 | 3. Resets `feature-branch` to `main`, then re-applies your commits one by one. 625 | - 🚫 Rewrites history (no merge commit). 626 | - ✅ Cleaner, linear history. 627 | 628 | **👉 `git merge main` (from `feature-branch`)** 629 | 630 | 1. Git finds the common ancestor between `feature-branch` and `main`. 631 | 2. Applies `main`'s changes onto `feature-branch`. 632 | 3. Creates a new **merge commit** combining both histories. 633 | - ✅ Preserves original history. 634 | - 📦 Keeps full branch context. 635 | 636 | ## Merge Conflicts with Rebase 637 | 638 | When you rebase a branch onto another branch, Git tries to apply the commits from the source branch onto the target branch. If there are conflicting changes between the two branches, Git will pause the rebase process and mark the conflicting files. You will need to manually resolve these conflicts before continuing with the rebase. 639 | 640 | ## Squash Commits Merge and Rebase 641 | 642 | **`git merge --squash feature`** 643 | 644 | **`git rebase -i HEAD~n`** 645 | The `git rebase -i HEAD~n` command allows you to interactively rebase the last n commits. This means you can choose which commits to keep, edit, squash (combine), or drop (remove) during the rebase process. The interactive rebase opens an editor where you can modify the commit history as needed. 646 | 647 | ## Cherry-Pick 648 | 649 | cherry-pick is a Git command that allows you to apply the changes introduced by a specific commit from one branch to another. This is useful when you want to incorporate a particular change without merging the entire branch. Cherry-picking creates a new commit in the target branch with the same changes as the original commit, but it does not affect the commit history of the source branch. 650 | To cherry-pick a commit, you need to know its commit hash. You can find the commit hash by running `git log` or `git log --oneline`. Once you have the hash, switch to the target branch where you want to apply the changes and run `git cherry-pick `. This will create a new commit in the target branch with the changes from the specified commit. 651 | To cherry-pick multiple commits, you can specify a range of commits using the `..` notation, like `git cherry-pick ..`. This will apply all commits in that range to the current branch. If there are conflicts during the cherry-pick process, Git will pause and allow you to resolve them before continuing. 652 | 653 | ## 🧠 Git Challenge: Conflicts, Rebase, Squash & Cherry-Pick 654 | 655 | - Create a new folder called `git-merge-rebase-practice` 656 | - Open the folder in VSCode 657 | - Open the terminal in VSCode (`View > Terminal` or `Ctrl + ``) 658 | - Initialize a Git repository 659 | - Create a file `main.txt`, add content, stage, and commit 660 | - Create a new branch `feature`, switch to it 661 | - Modify the same line in `main.txt`, commit the change 662 | - Switch back to `main`, edit the same line differently, and commit 663 | - Switch to `feature` create new file `feature-1.txt` and make a commit 664 | - Try merging `main` into `feature` — resolve the merge conflict manually 665 | - Stage the resolved file and complete the merge 666 | - Try merging `feature` into `main`, squash commits 667 | - Reset the repo to an earlier state (before feature branch) and repeat the scenario using rebase instead 668 | - Create a few more commits with small changes 669 | - During rebase, resolve conflicts and continue the process 670 | - Use interactive rebase to squash multiple commits into one 671 | - Verify the new, clean history 672 | - Create a new branch `cherry-target` 673 | - Switch back to `feature`, create and commit a unique change 674 | - Use `git log` to find the commit hash of this change 675 | - Switch to `cherry-target` and cherry-pick the commit using its hash 676 | - Verify that the changes appear on `cherry-target` 677 | - If conflicts appear, resolve and continue the process 678 | 679 | ## Github 680 | 681 | - largest development platform 682 | - cloud hosting & collaboration provider 683 | - git repository hosting 684 | 685 | - `git remote add origin URL` - Adds a remote repository to your local Git repository 686 | - `git push` - Uploads your local commits to the remote repository 687 | - `git fetch` - Downloads changes from remote without merging them 688 | - `git pull` - Downloads and integrates remote changes into your local repository 689 | - `git clone` - Creates a local copy of a remote repository 690 | 691 | 1. `git remote add origin URL` 692 | 693 | - Adds a remote repository (like GitHub) to your local Git repository 694 | - you're essentially creating a connection between your local project and a copy of that project hosted on a remote server (like GitHub). Think of it like setting up a two-way street between your computer and the serve 695 | - `origin` is the default name for the remote repository that serves as an alias for later use 696 | - The URL is typically the HTTPS or SSH link to your GitHub repository 697 | - Example: `git remote add origin https://github.com/username/repo.git` 698 | 699 | 2. `git push` 700 | 701 | - Uploads your local commits to the remote repository 702 | - Syncs your local changes with the remote repository 703 | - Common usage: `git push origin main` (pushes to main branch, typically for personal projects) 704 | - First time push: `git push -u origin main` (sets up tracking) 705 | - For production projects: `git push origin feature` (pushes to feature branch) 706 | - For production projects: `git push -u origin feature` (pushes to feature branch) 707 | - `git push -u origin main` - shorthand for the command below 708 | - `git push --set-upstream origin main` 709 | 710 | 3. `git fetch` 711 | 712 | - Downloads changes from the remote repository without merging them 713 | - Updates your remote-tracking branches 714 | - Common usage: `git fetch origin` (fetches all branches) 715 | - For specific branch: `git fetch origin feature` (fetches only feature branch) 716 | - Safer than pull as it doesn't automatically merge changes 717 | 718 | 4. `git pull` 719 | 720 | - Downloads and integrates changes from the remote repository 721 | - Combines `git fetch` and `git merge` in one command 722 | - Updates your local repository with remote changes 723 | - Common usage: `git pull origin main` (for main branch) 724 | - For feature branches: `git pull origin feature` (pulls changes from remote feature branch) 725 | 726 | 5. `git clone` 727 | - Creates a copy of a remote repository on your local machine 728 | - Downloads the entire repository history 729 | - Sets up remote tracking automatically 730 | - Example: `git clone https://github.com/username/repo.git` 731 | 732 | `git fetch` downloads new changes from the remote repository but doesn't apply them to your work. It's like getting updates but keeping them separate until you're ready to use them. `git pull` does both downloading and applying the changes in one step - it fetches the updates and immediately merges them into your current work. While `git pull` is more convenient, `git fetch` gives you more control as you can review changes before deciding to merge them. 733 | 734 | ## Create Github Account 735 | 736 | ## Setup SSH key 737 | 738 | [Setup SSH Key](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/adding-a-new-ssh-key-to-your-github-account) 739 | [Check For Existing SSH Key](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/checking-for-existing-ssh-keys) 740 | [Generate New SSH Key](https://docs.github.com/en/authentication/connecting-to-github-with-ssh/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent) 741 | 742 | - `ls -al ~/.ssh` - Lists all files (including hidden) in the SSH directory 743 | - `ls -la` - Lists all files in current directory with details 744 | - find `.ssh` 745 | - `cd .ssh` - Changes directory to .ssh folder 746 | - `ssh-keygen -t ed25519 -C "yourgithubemail@email.com"` - Generates new SSH key with your email 747 | - `ls -la` -Lists all files in current directory with details 748 | - `pbcopy < ~/.ssh/your_key.pub` - Copies public key to clipboard (macOS) 749 | - add public key to Github (Settings/SSH and GPG Keys) 750 | - `ssh -T git@github.com` - Tests SSH connection to GitHub 751 | - `ssh -T git@github.com -v` - Tests SSH connection with verbose output 752 | 753 | This should work. If it doesn't, try the steps below: 754 | 755 | - `touch ~/.ssh/config` - Creates SSH config file 756 | - `vim config` - Opens config file in vim editor 757 | 758 | ``` 759 | Host github.com 760 | AddKeysToAgent yes 761 | IdentityFile ~/.ssh/your_file 762 | ``` 763 | 764 | - `ssh-add ~/.ssh/your_file` - Adds SSH key to SSH agent 765 | - `ssh-add -l` - Lists all keys in SSH agent 766 | - `git config --global url."git@github.com:".insteadOf "https://github.com/"` - Configures Git to use SSH instead of HTTPS 767 | 768 | ## First GitHub Repository 769 | 770 | - create project locally, make one commit 771 | - create new project on Github 772 | - choose ssh option 773 | - explore commands 774 | - run commands on your machine, push the project up to Github 775 | 776 | - `git remote add origin yourValue.git` 777 | - `git branch -M main` 778 | - `git push -u origin main` 779 | 780 | - make second commit, push up to Github 781 | - `git push` 782 | 783 | ## Clone Remote Repository 784 | 785 | - clone repo 786 | - make another commit, push up to Github 787 | 788 | ## Create Github Repo with VSCode 789 | 790 | - create another project 791 | - make a commit 792 | - publish a branch from VSCode 793 | 794 | ## Extra - Publish Site on Netlify 795 | 796 | [Netlify](https://www.netlify.com/) 797 | 798 | ## First PR 799 | 800 | A Pull Request (PR) is like a formal request to merge your changes into someone else's project. It's the main way to contribute to open-source projects or collaborate with team members. When you create a PR: 801 | 802 | 1. You're telling the project maintainers "I've made some changes, please review them" 803 | 2. They can review your code, suggest improvements, or approve it 804 | 3. If approved, your changes get merged into the main project 805 | 806 | Think of it like submitting a draft for review before it gets published in a book. The maintainers can review your work, request changes, or accept it as is. 807 | 808 | - clone any of the repositories 809 | - create a branch 810 | - add some changes 811 | - push it up to Github 812 | 813 | ## Challenge - Second PR with `TICKET-22` Branch 814 | 815 | - checkout branch `TICKET-22` 816 | - create file ticket-22.txt with some text 817 | - add "hello people" to main-01.txt 818 | - change text to "hello from ticket-22" in `hello.js` 819 | - make a commit "TICKET-22 make changes" 820 | - create app.js 821 | - add text to "app is running..." in app.js 822 | - make a second commit "TICKET-22 change text in app.js" 823 | - merge `main` into `TICKET-22` 824 | - hmm. strange it's up to date ⚠️ 825 | - push the changes up to Github 826 | - see if you can merge `TICKET-22` into `main` ⚠️ 827 | - don't force it, keep watching and I will provide solution ⚠️ 828 | 829 | ## How Git Remotes and Remote-Tracking Branches Work 830 | 831 | - checkout main branch 832 | - see all branches (including remote) with VSCode GUI 833 | - "sync changes" button and "branch" in the left bottom corner 834 | - `git branch -a` - Lists all branches (both local and remote) in the repository 835 | 836 | In Git, a remote is like a link to a version of your project stored on another computer, usually a server like GitHub. It lets your local Git talk to that remote copy, so you can download updates (git fetch, git pull) or send your changes (git push). 837 | 838 | To help manage this, Git creates remote-tracking branches like remotes/origin/main. These are local snapshots that show what the remote branch looked like the last time you connected. They're read-only references that help Git keep track of the state of the remote repository, so you can compare, sync, or update your local branches without immediately changing them. 839 | 840 | These references get updated in three main ways: 841 | 842 | 1. **`git fetch`** 843 | 844 | - `git fetch` or `git fetch origin` 845 | - Contacts the remote. 846 | - Downloads new commits and branch updates. 847 | - Updates ALL `remotes/origin/*` branches to reflect the latest state of the remote. 848 | - Does **not** change your local working files or branches. 849 | - `git status` - to check status 850 | 851 | 2. **`git pull`** 852 | 853 | - Performs a `git fetch` followed by a merge (or rebase) ONLY into your current branch. 854 | - Updates the `remotes/origin/*` references, since we run `git fetch` 855 | - Also updates your current branch if there are new changes. 856 | 857 | 3. **`git push`** 858 | - Sends your local commits to the remote repository. 859 | - After a successful push, updates the corresponding `remotes/origin/` in your local repo. 860 | - Only updates the tracking branch for the branch you pushed. 861 | 862 | In summary: 863 | 864 | - Use `fetch` or `pull` to get updates **from** the remote. 865 | - Use `push` to send your work **to** the remote. 866 | - Remote-tracking branches only update when one of these commands is run. 867 | 868 | **`remotes/origin/HEAD -> origin/main`** 869 | to indicate which remote branch is the default (usually main or master). 870 | 871 | ## Complete Challenge 872 | 873 | - run `git pull` in `main` branch 874 | - switch to `ticket-22` branch 875 | - squash commits, with interactive rebase 876 | - rebase on top of `main` 877 | - try to push to Github 878 | 879 | After a rebase, Git rewrites your branch's commit history, creating new commit hashes. Because your local history no longer matches the remote, a regular git push will fail with a "non-fast-forward" error. To update the remote with your rebased changes, you need to use git push -f (force), which tells Git to overwrite the remote branch with your new history. This should be done carefully, especially on shared branches, as it can overwrite others' work. 880 | 881 | - `git push -f` 882 | 883 | I know my history changed — overwrite the remote branch with my local version anyway. 884 | ⚠️ Be careful: 885 | Force-pushing can overwrite others' work if you're not the only one working on the branch. 886 | 887 | - leave comments 888 | - merge `TICKET-22` branch back into the `main` branch on Github. 889 | 890 | **`git push -u origin branch`** 891 | 892 | The `-u` flag in `git push` stands for `--set-upstream` and is used to link your local branch with a remote branch. When you push a new branch for the first time using `git push origin feature-xyz`, Git will push the code but won't remember which remote branch it should track. This means future `git pull` or `git push` commands will require you to specify the remote and branch name again. However, if you use `git push -u origin feature-xyz`, Git not only pushes the branch but also sets it to track `origin/feature-xyz`. This makes future pushes and pulls simpler, as Git now knows which branch to use by default. You only need to use the `-u` flag once when creating and pushing a new branch. 893 | 894 | In short it's useful since we need to run only `git pull` or `git push` after. 895 | 896 | **Pushing a Local Branch to a Remote with a Different Name** 897 | 898 | When you run `git push -u origin payment` but don't have a local branch named `payment`, Git throws an error: `src refspec payment does not match any`. This is because Git assumes you're trying to push a local branch called `payment`, which doesn't exist. If you're on a local branch named `feature` and want to push it to the remote as `payment`, you need to explicitly tell Git by using: `git push -u origin feature:payment`. This pushes your local `feature` branch to a remote branch named `payment` and sets up tracking between them. 899 | 900 | ## 🧠 Github Challenge 901 | 902 | - Create a folder named `temp-github-challenge` and initialize a Git repository. 903 | - Create a file `app.js` with a simple `console.log()` statement. 904 | - Stage and commit the file as the initial commit on the `main` branch. 905 | - Create a new GitHub repository and push the project to `main`. 906 | 907 | - Clone the GitHub repository into three separate folders: `dev1`, `dev2`, and `dev3`. 908 | 909 | - In the `dev1` folder: 910 | 911 | - Create a branch named `TICKET-11`. 912 | - Modify `app.js` by changing the console message. 913 | - Commit the change with a short message. 914 | - Fetch and merge the latest `main` into `TICKET-11`. 915 | - Push the branch to GitHub. 916 | - Create a pull request and merge `TICKET-11` into `main` using the **merge** strategy. 917 | 918 | - In the `dev2` folder: 919 | 920 | - Create a branch named `TICKET-22`. 921 | - Make two separate changes to `app.js`, committing after each change. 922 | - Fetch and merge the latest `main` into `TICKET-22`. 923 | - Push the branch to GitHub. 924 | - Create a pull request and merge `TICKET-22` into `main` using the **merge** strategy. 925 | 926 | - In the `dev3` folder: 927 | 928 | - Create a branch named `TICKET-33`. 929 | - Make three separate changes to `app.js`, committing after each. 930 | - Use interactive rebase to squash all three commits into one. 931 | - Fetch the latest `main` and rebase `TICKET-33` on top of it. 932 | - Force push the rebased branch to GitHub. 933 | - Create a pull request and merge `TICKET-33` into `main` using the **rebase** strategy. 934 | 935 | **🍒 Cherry-Pick Across Branches with Remote Fetch** 936 | 937 | - create new project `temp-production` 938 | - add new file `main-01.txt` with some content, make a commit, push it up to Github 939 | - clone two projects `dev1` and `dev2` 940 | 941 | - In `dev1` project: 942 | 943 | - Create a branch named `FEATURE`. 944 | - Create a new file `feature-01.txt` and add some content, commit the change, push it up to Github 945 | - repeat with files `feature-02.txt` and `feature-03.txt` 946 | 947 | - Switch to the `dev2` folder: 948 | 949 | - Create a branch named `CHECKOUT`. 950 | - Create a file `checkout.txt` and add some content. 951 | - Commit the change. 952 | 953 | - Navigate to the GitHub repo in your browser: 954 | 955 | - Open the `FEATURE` branch and copy the commit hash for the `feature-03.txt` commit. 956 | 957 | - Back in `dev2` on the `checkout` branch: 958 | 959 | - Try to cherry-pick the `feature-03.txt` commit using the copied hash. 960 | - Notice the error (Git can't find the commit because it doesn't exist locally). 961 | 962 | - Fix the error by running `git fetch`: 963 | 964 | - This updates the remote-tracking branches (e.g., `origin/FEATURE`) without changing any local branches. 965 | 966 | - Retry the cherry-pick: 967 | - Now it works because the commit is known locally via the updated remote reference. 968 | --------------------------------------------------------------------------------