Catalyst

Git

Revision control for humans
### Introduction * The format of this course is mostly a tutorial (with some lecturing thrown in) * The tutorial is based on the commandline * The tutorial is designed to uncover the concepts * Not to provide all the command syntax Note: Most complex things in git are just a convenient combination of simple things. Hopefully if you are armed with the concepts, the internet will help you find the specifics you need.
### What is Git? * A tool for recording the history of changes made to files. * Any kind of files! * Most commonly used for managing source code.
## Why use Git?
### 1. Keep backups of your files. With Git, you can keep rolling backups of your project files. You can revert back to a previous version at any time. You can go ahead and make lots of experimental changes, knowing a stable version of your code is safely recorded.
### 2. Facilitate collaboration You can share files with your team or a even wider community with Git. Team members can edit files independently and at the same time, then combine their changes later.
### 3. Track file history Every time a change is recorded in Git, the date, author, and a description of changes is recorded. So you can: * Find out *when* the code was broken. * Find out *who* broke the code. * Find out *why* they broke they code.
### Alternatives to Git? Git is known as a version control system (VCS), and there are many others: * RCS * CVS * Subversion (SVN) * Darcs * Perforce * Bazaar * Mercurial * ...
### Reasons to use Git? * **It is currently the most popular VCS** * It is fast * Branching and merging is trivial * You can be disconnected from the network, yet still continue working * It does not dictate your workflow * [It protects your data](http://git-scm.com/about/info-assurance) * Once you master the concepts, you can do some really creative (and useful!) stuff
### Installing ```bash # Required $ sudo apt-get install git ``` ```bash # Recommended $ sudo apt-get install gitk git-gui ``` Note: Pause here to explain the way we are showing commands * talk about '$' as the prompt, etc
### Installing (alternative OS) * Go to [git-scm.org](http://git-scm.org "The home of git") * Find the [Download link](http://git-scm.com/downloads "install instructions") * Follow the instructions for your OS * For MS Win, you should probably choose "Git BASH" when installing
### Getting help ```bash # git help COMMAND $ git help status # man git-COMMAND $ man git-status ``` Note: The COMMANDs we have used so far are 'init' and 'status', so....
### Create a new repository ```git init``` ```bash $ mkdir test ``` ```bash $ cd test ``` ```bash $ git init Initialized empty Git repository in .git/ ``` Check the status with ```git status``` ```bash $ git status # On branch master # # Initial commit # nothing to commit (create/copy files and use "git add" to track) ```
### What did that do? ```bash ls -a # .git ``` Git is just a bit different from other revision control systems ![overview](images/local-remote-small.png "overview") Note: The 'staging area' is often called the 'index' We refer to the 'working directory' as what we have 'checked out' Some VC's don't make a distinction between local and remote. Draw diagram (we'll come back to it often): * Working directory - you know this * Repo - The series of snapshots/commits that Git keeps. If changes are in here, they are safe. * Staging area - You can choose what you want to commit. E.g. working on many issues. Craft your commits.
### Global configuration settings Before we start... ```bash # We need to tell git who you are - But it's OK to lie.... $ git config --global user.name "Jed I. Night" $ git config --global user.email "null@catalyst.net.nz" ``` ```bash # If you have a favourite editor. $ git config --global core.editor gedit ``` ```bash # If you will be working on windows, but need to deal with unix # NOTE: You only need these on Windows. $ git config --global core.autocrlf true # Convert Windows line endings to Unix line endings in Git. $ git config --global core.longpaths true # Makes it possible to work on repositories with filenames that exceed Windows limits. ``` Note: You can use tab to autocomplete in bash.
### Project configuration settings This will tell Git you like to see pretty colours on the screen ```bash $ git config color.ui auto ``` Note: These settings will override the global settings - but only within the current repository (which is test)
### Accessing the configuration settings Global data is stored in ```$HOME/.gitconfig``` Project data is stored in ```$PROJECT/.git/config``` ```bash # Use `git config` to see it $ git config -l ``` ```bash # ..or just edit the files $ gedit ~/.gitconfig $ gedit test/.git/config ```
### Managing Files Make some changes... ```bash $ touch myscript.pl ``` ```bash $ git status # On branch master # # Initial commit # # Untracked files: # (use "git add <file>..." to include in what will be committed) # # myscript.pl nothing added to commit but untracked files present (use "git add" to track) ```
### Tell Git to track those files ```git add``` ```bash $ git add myscript.pl ``` ```bash $ git status # On branch master # # Initial commit # # Changes to be committed: # (use "git rm --cached <file>..." to unstage) # # new file: myscript.pl # ``` Note: This actually adds the file to the 'index'
### Change an existing file Make some changes... ```bash $ echo DATA > myscript.pl ``` ```bash $ git status # On branch master # # Initial commit # # Changes to be committed: # (use "git rm --cached <file>..." to unstage) # # new file: myscript.pl # # Changed but not updated: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: myscript.pl # ``` Note: This is our first clue that Git tracks changes rather than files
### See what you have done ```git diff``` ```bash $ git diff --- a/myscript.pl +++ b/myscript.pl @@ -0,0 +1 @@ +DATA ```
### Change an existing file We need to tell Git that you intend to commit the checked out version, with ```git add``` ```bash $ git add myscript.pl ``` ```bash $ git status # On branch master # # Initial commit # # Changes to be committed: # (use "git rm --cached <file>..." to unstage) # # new file: myscript.pl # ```
### Committing changes Commit your work with ```git commit``` ```bash $ git commit myscript.pl Created commit ae54011: Add a message. 1 files changed, 3 insertions(+), 0 deletions(-) create mode 100644 myscript.pl ``` You will be stuck in an editor so you can input a commit message. Normally, you WILL make your commit message meaningful! Note: We have told git about our changes, but we haven't actually committed anything yet. This is deliberate - so you can build up more complex commits.
### Committing changes - some options You don't have to ```git add``` all your changes manually ```bash # Add <file>, and then commit $ git commit <file> ``` ```bash # Add all your changes, and then commit $ git commit -a ``` ```bash # You can have an different editor... $ EDITOR=gedit git commit -a ``` ```bash # You don't have to use an editor at all... $ git commit -m 'commit message goes here' ```
### Managing Files - Permissions Oops, that file isn't executable ```bash $ chmod 755 myscript.pl ``` ```bash $ git commit myscript.pl Created commit 378af93: Make it executable. 0 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 myscript.pl ```
### Managing Files - Move To rename a file use ```git mv``` ```bash $ git mv myscript.pl README.txt ``` ```bash $ git status # On branch master # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # renamed: myscript.pl -> README.txt # ``` This has changed our checkout, and the index, so we are ready to commit the change ```bash $ git commit Created commit fabd446: Rename the file. 1 files changed, 0 insertions(+), 0 deletions(-) rename myscript.pl => README.txt (100%) ```
### Managing Files - Delete To delete a file use ```git rm``` ```bash # This won't actually work, because we haven't # created "another-script.pl" # ... but you can try it, if you like.... $ git rm -f another-script.pl ``` ```bash $ git status # On branch master # Changes to be committed: # (use "git reset HEAD <file>..." to unstage) # # deleted: another-script.pl # ``` And commit the change ```bash $ git commit Created commit bd10c5f: Remove another-script.pl 0 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 another-script.pl ```
### Managing Files - ignore them ```bash # Let's imagine your editor keeps creating '.swp' files $ touch README.txt.swp ``` ```bash $ git status # On branch master # Untracked files: # (use "git add <file>..." to include in what will be committed) # # README.txt.swp ```
### Managing Files - ignore them ```bash # Add a line that conatins '*.swp' $ gedit .gitignore ``` ```bash $ git status # On branch master # Untracked files: # (use "git add <file>..." to include in what will be committed) # # .gitignore ``` ```bash # We can then commit the .gitignore file $ git add .gitignore $ git commit -m 'Created a .gitignore file' ``` Note: You can put a different .gitignore file in each directory ...or stick to one in the root of your project
### Ignoring files Locally vs. Globally * Adding things to .gitignore will ignore them for all users! * Instead you can ignore things locally using .git/info/exclude.
### Tags Tags work pretty much like you would expect. They allow you to mark specific points in history as being important. Often people use this functionality to mark release points. ```bash # Lightweight tag $ git tag v1.0 # Annotated tag $ git tag v1.0-production -m 'this might be important later!' ``` ```bash $ git tag $ git show v1.0 $ git show v1.0-production ``` Note: 2 types of tags: lightweight and annotated Tags don't get shared, by default. Also, explain that you can git show anything (tag, branch, sha1, etc).
### Change Logs Use ```git log``` ```bash $ git log commit 09f90bc2a74f7ca2f825c4a386e168649b9fec97 Author: Evan Giles Date: Thu Dec 16 11:53:48 2010 +1300 Rename the file. commit f7123c5ffdccbed11b50b0b74a181186e1a13028 Author: Evan Giles Date: Thu Dec 16 11:53:25 2010 +1300 Make it executable commit 8657bea3230587abdcbe39e6bf699c9ee8f505a6 Author: Evan Giles Date: Thu Dec 16 11:52:51 2010 +1300 Add a message. ``` By default the output is piped into $PAGER
### Change Logs ```bash # You can change the output format $ git log --pretty=oneline ``` ```bash # Or specify which file or directory you are interested in $ git log README.txt ``` ```bash # There are lots of options.. $ git log --pretty=oneline --since='5 minutes ago' ```
### Change Logs - Annotate Show who made changes to what line ```bash $ git annotate filename.pl b61863c8 (Andrew R. 2008-05-09 17:01:41 +1200 1) #!/usr/bin/perl -w b61863c8 (Andrew R. 2008-05-09 17:01:41 +1200 2) b61863c8 (Andrew R. 2008-05-09 17:01:41 +1200 3) print "silly script\n"; 9c08faf4 (Bad Coder 2008-05-09 17:18:18 +1200 4) I'm in ur code, breaking ur stuff. ```
Who is this Bad Coder fella?
Better remembered as ```git blame``` ```bash $ git blame filename.pl b61863c8 (Andrew R. 2008-05-09 17:01:41 +1200 1) #!/usr/bin/perl -w b61863c8 (Andrew R. 2008-05-09 17:01:41 +1200 2) b61863c8 (Andrew R. 2008-05-09 17:01:41 +1200 3) print "silly script\n"; 9c08faf4 (Bad Coder 2008-05-09 17:18:18 +1200 4) I'm in ur code, breaking ur stuff. ```
### Change logs - GUI Not strictly change logs, but... gitk / qgit / gitg / etc ![image](images/gitk.png "gitk")
### Some more concepts - commits * It is important to understand that git thinks in ```commits``` * Each commit refers to a previous commit (its parent) * Commits can be referenced by their SHA1 checksum * or an abbreviation of it * or by a number of things that might refer to them * ```gitk``` lets you visualise the commit history, which helps a lot

Commits are....

Totally unchangeable!
### Branches * Branches are useful for trying experimental changes or refactoring without affecting your main branch. * Many (most) projects have a branch for each release * Branches happen (without even trying) when several people try to work on the same project - but I'll explain that soon ;) Think of a branch as a "movable pointer" to a specific commit.
### Branching - List To show branches use ```git branch``` ```bash $ git branch * master ``` Only one branch, called ```master``` The '*' indicates that it is your current branch: The branch that is "checked out". Each local repo has a special pointer called HEAD, which points to the currently checked out branch. Note: You can also use 'git status' It is useful to think of branches as an 'alternative reality'
### Branching - Create Use ```git branch``` (or ```git checkout -b```) ```bash $ git checkout -b new-branch Switched to a new branch "new-branch" ``` Will create "new-branch", and check it out for you ```bash $ git branch master * new-branch ``` Note: mention that 'git checkout' is a convenience interface ...it does several things in one step.
### Branching - Create somewhere else By default a new branch will be created at the commit you already have checked out You can also create a new branch at another commit ```bash $ git checkout -b another-branch master Switched to a new branch "another-branch" ``` ```bash $ git branch * another-branch master new-branch ``` Note: Here, the checkout command is actually doing 3 things - go the the master branch - make a branch there (callled 'another-branch') - checkout the 'another-branch' branch
### Branching - Change Branch Use ```git checkout``` ```bash $ git checkout new-branch Switched to branch "new-branch" ``` ```bash $ git branch another-branch master * new-branch ``` Note: Don't forget to see how this is shown in ```gitk```
### Branching - What's the deal? ```bash # Make a change to a file (and commit that change) $ echo "... From new-branch" >> README.txt $ git commit README.txt Created commit a6ed2cf: From new-branch 1 files changed, 1 insertions(+), 0 deletions(-) ``` ```bash # Check the file.. $ cat README.txt DATA ... From new-branch ``` ```bash # Jump to another branch $ git checkout master Switched to branch "master" ``` ```bash # The text we added ain't there $ cat README.txt DATA ```
### Merging - Simple Case You should now be on the master branch ```bash $ git status # On branch master nothing to commit (working directory clean) ``` Use ```git merge``` ```bash $ git merge new-branch Updating e766bfb..a6ed2cf Fast forward README.txt | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) ``` In this case, we have done a ```fast forward``` merge If there are no conflicts, this may make a new commit object use ```gitk``` to see what happened Note: - We are merging changes *IN*, from somewhere else - explain the fast forward bit - talk about merges being line by line, so not for binary data
### Merging - get ready for a conflict Conflicts are more difficult (lets create one) ```bash # Make a change to a file, commit that change to 'master' $ echo "New value for data" > README.txt $ git commit -a -m 'update script with a new value' # Change branches, make a change, and commit $ git checkout new-branch $ echo "different value for data" > README.txt $ git commit -a -m 'update script with a different value' # Go back to the master branch, if we try to merge - there # will be a problem! $ git checkout master ```
### Merging - you can't do that If there is a conflict then git will stop and make you fix it. ```bash $ git merge new-branch Auto-merged README.txt CONFLICT (content): Merge conflict in README.txt Automatic merge failed; fix conflicts and then commit the result. ``` ```bash $ git status # On branch master # Unmerged paths: # (use "git add/rm <file>..." as appropriate to mark resolution) # # both modified: README.txt # no changes added to commit (use "git add" and/or "git commit -a") ``` ```bash $ cat README.txt <<<<<<< HEAD:README.txt New value for data ======= different value for data >>>>>>> new-branch:README.txt ``` Note: Mention git merge --abort
### Merging - Fixing conflicts Lots of tools to help fix things up. Hand edit, xxdiff, smartmerge, etc We'll just fix it by editing the file ```bash $ gedit README.txt $ cat README.txt New, different value for data ``` But Git still won't allow us to continue... ```bash $ git commit U README.txt fatal: 'commit' is not possible because you have unmerged files. Please, fix them up in the work tree, and then use 'git add/rm <file>' as appropriate to mark resolution and make a commit, or use 'git commit -a'. ```
### Merging - Success at last We need to tell Git that it has been fixed before we commit ```bash $ git add README.txt $ git commit Created commit a411f2a: Merge branch 'new-branch' ``` In this case the commit message is automatically created, but you can edit it if you want. ```bash Merge branch 'new-branch' Conflicts: README.txt ```
### Merging - How does it look? Looking at the trees in gitk helps you understand stuff. ```bash $ gitk ```

A quick recap

Sharing your changes with others

### Creating Repositories - Revisited We already know how to create a new repository ```bash $ git init Initialized empty Git repository in .git/ ``` ...but normally, you want to join in with an existing project
### Clone an existing repository In practise, you're more likely to use ```git clone```. To check out the source code of a random project: ```bash $ cd ~ $ git clone https://github.com/catalyst-training/git-basic Cloning into git-basic... remote: Counting objects: 90, done. remote: Compressing objects: 100% (43/43), done. remote: Total 90 (delta 44), reused 90 (delta 44) Receiving objects: 100% (90/90), 31.62 KiB, done. Resolving deltas: 100% (44/44), done. ``` ```bash $ cd git-basic ``` ```bash $ ls ``` ```bash $ gitk ``` Note: git remote -v
### Remote repositories - URLs ```bash # Clone an existing repository via HTTP $ git clone https://github.com/catalyst-training/git-basic ``` ```bash # Clone an existing repository via SSH $ git clone ssh://git.catalyst.net.nz/git/public/git.git ``` ```bash # Clone an existing local repository (this is only slightly mad) $ git clone test test2 ```
### Remote branches Remote branches are references (pointers) to the state of branches in your remote repositories. They're local branches that you can't move; they're moved automatically for you whenever you do any network communication. Remote branches act as bookmarks to remind you where the branches on your remote repositories were the last time you connected to them.
### Origin You can see all branches (including the remote ones) with the ```git branch``` command ```bash $ cd git-basic/ $ git branch -a * master remotes/origin/master ``` Note: you don't need to type 'remotes' to refer to these branches
### Other remotes You can manipulate your view of other repositories with the ```git remote``` command ```bash $ git remote add duplicate https://github.com/catalyst-training/git-basic $ git remote show duplicate origin ``` ```bash $ git fetch --all Fetching origin Fetching duplicate From https://github.com/catalyst-training/git-basic * [new branch] gh-pages -> duplicate/gh-pages * [new branch] master -> duplicate/master ``` Note: origin is not special, except that: - it is created by default when you clone a repository - some commands (like fetch) assume you mean origin if you don't specify the remote - etc, etc
### Ways to work with git (1) #### Corporate Workflow You will probably use this
corporate
### Ways to work with git (2) #### Integration manager Workflow A quick diversion: http://www.github.com
github
### Ways to work with git (3) #### Dictator Workflow This is how the Linux kernel is managed
linux
### Ways to work with git (4) #### Peer to peer Workflow
p2p
#### Once upon a time.... Alice and Bob wanted to do some work
So they both made some changes....
Alice pushes her changes...
But Bob has a problem...
Now Bob needs to fetch the changes from Alice
and merge them with his work
They all lived happily ever after...
### Now we can try it out ```bash $ touch .git/git-daemon-export-ok # Set up an alias once to be able to serve your repo on the network. $ git config --global alias.serve "daemon --verbose --export-all --base-path=.git --reuseaddr --strict-paths --enable=receive-pack .git/" # Serve your repo. $ git serve ``` ```bash # In a new terminal. # Find your IP address to give your neighbour. $ ifconfig # Look for something like "inet addr:10.255.100.158" # Clone your neighbour's repository. $ cd ~ $ git clone git://$neighbour_ip/ test3 ``` ```bash # Update your own repository (after your neighbour has cloned it). $ cd ~/test $ gedit $YOURNAME.txt $ git add $YOURNAME.txt $ git commit ```
### Now we can try it out ```bash # Create a new file and commit in your cloned repository $ cd ~/test3 $ gedit $YOURNAME.txt $ git add $YOURNAME.txt $ git commit ``` ```bash # Try to push your changes to your neighbour's repository $ git push origin master ``` ```bash # You are now Bob! $ git fetch $ git merge origin/master ``` Note: Explain What is going on with "origin" and "master" here: - git push origin master - git merge origin/master Also introduce the idea that commands have defaults: - git push ... git push origin master - - -
### Changing your commits You can 'change' the most recent commit using ```git commit``` ```bash $ git add something.txt $ git commit --amend ``` This is quite a big deal... Note: Will someone please pull me up on this?! Explain how this works - That you are not changing anything here - just making a new commit which is quite like the old one - and then moving the labels around Warning: - Do not change commits that exist outside your repository. - If you do, people will hate you, and you'll be scorned by friends and family.
### Copy a commit You can copy a commit from one branch to another You might want to do this if, for example, a bug is discovered on your development branch that also needs to be applied to your production branch. ```bash $ git cherry-pick e43a6fd3e94888d76779ad79fb568ed180e5fcdf ``` Note: The commit created will look the same, but have a different commit id Note that the cherry-pick can fail, if there are conflicts
### Undo a commit You can undo a previous commit with ```git revert```. This makes a new commit, that is the exact opposite of a previous commit in your repository. The previous commit remains intact. ```bash $ git revert e43a6fd3e94888d76779ad79fb568ed180e5fcdf ``` ```bash $ git log --pretty=oneline 830d77273fc24c0708403102a05a5a5ffecfce93 Revert "Introduce bug" d7a1ee454168081227ee82c5f11bb08f77e2643d Unrelated change e43a6fd3e94888d76779ad79fb568ed180e5fcdf Introduce bug ``` Note: When you revert the commit, you get dropped into an editor in case you want to can edit the commit message..
### Getting serious with copying commits As an alternative to merging, you can use ```git rebase```. Instead of making a new commit which joins two branches together, it copies your changes on top of the other branch... You use it just like a merge. ```bash $ git rebase origin/master ``` Note: Draw what this does, contrast it with a merge
### Rebase vs. Merge > One point of view on this is that your repository's commit > history is a record of what actually happened. It's a historical > document, valuable in its own right, and shouldn't be tampered > with. From this angle, changing the commit history is almost > blasphemous; you're lying about what actually transpired. So > what if there was a messy series of merge commits? That's how > it happened, and the repository should preserve that for > posterity. Note: History is an audit trail
### Rebase vs. Merge > The opposing point of view is that the commit history is the > story of how your project was made. You wouldn't publish the > first draft of a book, and the manual for how to maintain your > software deserves careful editing. This is the camp that uses > tools like rebase and filter-branch to tell the story in the > way that's best for future readers. Note: History is a story > You should not change commits that exist outside your repository
### A more advanced rebase ```bash $ git rebase --interactive origin/master ``` ```bash pick a3895fe Try a bit harder to return a useful value from all methods pick 180e665 Release engineering (0.8) pick 2a6d832 Update Build.PL for newer build tools pick e1fac16 Use semantic versioning (http://semver.org/) # Rebase aa8a695..e1fac16 onto aa8a695 # # Commands: # p, pick = use commit # r, reword = use commit, but edit the commit message # e, edit = use commit, but stop for amending # s, squash = use commit, but meld into previous commit # f, fixup = like "squash", but discard this commit's log message # x, exec = run command (the rest of the line) using shell # # These lines can be re-ordered; they are executed from top to bottom. # # If you remove a line here THAT COMMIT WILL BE LOST. # However, if you remove everything, the rebase will be aborted. # ```
### Loose ends... #### git reset In it's simplest form, it allows you to throw away changes you have made locally. ```bash $ git status # On branch master # # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: index.html ``` ```bash $ git reset --hard HEAD is now at 5cc4a26 wr235825: small changes $ git status # On branch master nothing to commit (working directory clean) ```
### Loose ends... #### git reset ```bash # You can also change to a different commit before doing # the reset $ git reset --hard HEAD^^ HEAD is now at a51452d rewrite the 'begin' function ```
```bash # This changes your commit, but leaves your files and index untouched # - changes that you have 'added' are still ready to commit # - changes to files are still ready to add $ git reset --soft HEAD^^ ```
```bash # This changes your commit and the index, but leaves your files untouched # - changes to files are now ready to add, even if you had already added them $ git reset --mixed HEAD^^ ```
### Loose ends... #### git stash (hide) You can hide your changes away for later use ```bash $ git status # On branch master # # modified: myscript.pl $ git stash Saved working directory and index state WIP on master: 5cc4a26 added a file ``` ```bash $ git status # On branch master nothing to commit (working directory clean) ```
### Loose ends... #### git stash (restore) Later on, you can restore your changes ```bash $ git status # On branch master nothing to commit (working directory clean) $ git stash pop # On branch master # # Changes not staged for commit: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: myscript.pl no changes added to commit (use "git add" and/or "git commit -a") Dropped refs/stash@{0} (1a69a03f554a61ea50b3a9e2eb1182608cb50c8e) ``` Note: You can manage multiple stashes if you want....but that gets confusing :(
### Graphical interfaces #### A live demo! * Changes with gitk * Using git gui Note: Demonstrate how to: - gitk: change branches - gitk: reset - gitk: making a tag - gitk: integration with git-gui - git gui: making a commit - git gui: amend a commit -
### The End #### Questions?
The official Git site-> http://git-scm.com/about Data Assurance-> http://git-scm.com/about/info-assurance Cheat sheet-> http://web.archive.org/web/20090419122050/swxruby.org/git-cheat-sheet.pdf Github-> http://github.com ---------------------
The presentation content is licensed under a Creative Commons Attribution 3.0 License. (http://creativecommons.org/licenses/by/3.0)
The presentation display is licensed seperately by Hakim El Hattab / @hakimel
### Problem 1 #### Fix a production bug We have just discovered that there is a program in production that is not executable - the site is down! But we can't deploy the latest code because it's not ready... Please find the release tag 'release-1-0' in the repository 'https://github.com/catalyst-training/example1.git', and fix the bug! Note: Note that these problems are NOT a test - you haven't been given enough information yet It is just some everyday problems that we can work through together...
### Problem 1 #### Solution ```bash # Clone the repository $ cd ~ $ git clone https://github.com/catalyst-training/example1.git $ cd example1 # Make a new branch (at the point we want to change) $ git checkout -b release-1 release-1-0 # Fix the problem $ chmod +x program $ git commit -a -m 'make the program executable' $ # git push origin release-1 ``` Note: Discuss * The fact that we can't push to that URL * And even if we could, we can't push to the master branch * What would we normally do next (cherry-pick / merge), probably not rebase
### Problem 2 #### Change the past I have just noticed that https://github.com/catalyst-training/example2.git has a dodgey commit. The commit message is 'Oooh, this smells a bit funny...'. Please make it go away Note: Once again, you won't be able to push your changes - but that's ok.
### Problem 2 #### Solution ```bash # Clone the repository $ cd ~ $ git clone https://github.com/catalyst-training/example2.git $ cd example2 ``` ```bash # Work out what we want to do $ git log --oneline 5c90449 Remove the README file 3bec061 Some more stuff 3114205 Oooh, this smells a bit funny... 510043a Another list - snakes 6a624b3 Add a list of lists ``` ```bash # Rewrite the past $ git rebase --interactive 510043a ```
### Problem 2b #### Change the past, more! Wow, now that I see what you can do to tidy up the past, I realise I want more Please add your favourite movie to the list of movies - but make it look like it was added with all the other movies. Note: Once again, you won't be able to push your changes - but that's ok.
### Problem 2b #### Solution ```bash $ git log --oneline ``` ```bash # This will be more complex, from within this command you'll need to: # $ echo '* Highlander II' >> lists/movies.txt # $ git add lists/movies.txt # $ git commit --amend # $ git rebase --continue $ git rebase --interactive b9fb9c8 ```
### Problem 3 #### Join 2 repositories together We have been working as two teams for a while now, and we have realised that the two teams are so interlinked that we should be all working from the same repository, Please join https://github.com/catalyst-training/example1.git and https://github.com/catalyst-training/example2.git together! Of course, I would like to keep all files and history from both teams intact. Note: This is a true story
### Problem 3 #### Solution ```bash $ cd ~/example2 # Add another remote! $ git remote add ex1 https://github.com/catalyst-training/example1.git # Fetch the commits from example1 into this repo $ git fetch ex1 # Merge ex1/master into origin/master $ git merge ex1/master $ # git push origin master ``` Note: Discuss * If there were conflicts, we could resolve them, or put the projects into subdirs first * We could have used the directory /tmp/example1/.git as the URL for ex1 - that would have allowed us to include our bugfix into the merge * We still could!, and we could then cherry-pick our bugfix in!
### Problem 4 #### Github Please create a github account, then 'fork' the repository 'https://github.com/catalyst-training/example3' Then make a change, and create a pull request so I can accept your work. You can do the whole thing in your browser! Note: This will take a bit more time, help with - Github account - SSH keys - fork vs clone - editing inside the browser - pull requests - etc...
### Problem 4b #### Git Gui That was great, but now lets try again, using ```git-gui``` to make and push your commit. I'll get you started... ```bash $ cd ~ $ git clone https://github.com/YOURNAME/example3.git $ cd example3 $ echo 'Sean Connery' > $YOURNAME.txt $ git gui ```
### Problem 5 #### Mess with a remote branch Using your github account, push a 'password' to github. ```bash $ echo 'butter' > password.txt $ git add password.txt $ git commit -m "I may regret this...." $ git push origin master ``` Now make it go away. There are several ways to do this, but is it really gone?
### Problem 5 #### Solution ```bash # Amend the commit and force push $ echo '' > password.txt $ git commit -am "Nothing to see here..." $ git push -f origin master ```
```bash # Rewind and force push $ git reset --hard HEAD^ $ git push -f origin master ```
```bash # Delete the remote branch and push a new one $ git push origin :master $ git reset --hard HEAD^ $ git push origin master ```
### Problem 6 #### Abort a merge Go to your 'example2' project, and try to merge in the 'kittens' branch... ```bash # Create a conflict $ cd ~/example2 $ git merge origin/kittens $ git status ``` Oh, no, there are conflicts! Get me out of here! Note: or a rebase ...
### Problem 6 #### Solution ```bash # Too hard, I'll try again some other time $ git merge --abort ```
### Problem 6b #### Use tools to try to resolve a conflict Go to your 'example2' project, and try to merge in the 'kittens' branch... ```bash # Create a conflict $ cd ~/example2 $ git merge origin/kittens $ git status ``` There are conflicts, but I think you can handle them!
### Problem 6b #### Solution ```bash # Let's give it a go... $ sudo apt-get install meld $ git mergetool ``` Note: Also, we should try this again after installing 'meld'
### Problem 7 #### Throw away your changes What if you make some changes, and you want to get back to safety? ```bash $ cd /tmp/example2 $ echo 'A dragon will fix it' > lists/links.txt $ rm lists/movies.txt $ git status ```
### Problem 7 #### Solution ```bash $ git reset --hard ``` Note: Could we use git-reset? git-checkout? gitk? git-clean?
### The End #### That's really it this time Note: Extra things to discuss, to fill in time: - Setting up a bare repo - git add/commit -p - git bisect - git reflog