Version Control with Git xkcd.com/1597

Embed Size (px)

DESCRIPTION

Project changes over time: Old? New? Both? Problem 1: Progress stuff.h awesome.h things.c stuff.h awesome.h things.c awesome.h things.c initial effort (last month) add stuff (last week) change stuff (yesterday) When was some feature added? Why? Maintain previous version while working on new? Fix the same bug once in old and new version?

Citation preview

Version Control with Git xkcd.com/1597 Every project has 2 problems stuff.h awesome.h things.c Project changes over time: Old? New? Both? Problem 1: Progress stuff.h awesome.h things.c stuff.h awesome.h things.c awesome.h things.c initial effort (last month) add stuff (last week) change stuff (yesterday) When was some feature added? Why? Maintain previous version while working on new? Fix the same bug once in old and new version? Project changes over time: Old? New? Both? Problem 1: Progress stuff.h awesome.h things.c stuff.h awesome.h things.c awesome.h things.c initial effort (last month) add stuff (last week) change stuff (yesterday) When was some feature added? Why? Maintain previous version while working on new? Fix the same bug once in old and new version? Many peoples version-control method of choice is to copy files into another directory (perhaps a time- stamped directory, if theyre clever). This approach is very common because it is so simple, but it is also incredibly error prone.Pro Git Difficult even if you are the only one! But collaboration is totally impractical, because of Multiple, simultaneous changes: Laptops? Colleagues? Problem 2: Edit Wars stuff.h awesome.h things.c stuff.h awesome.h things.c int main(){} int foo(){} ??? int main(){} void foo(){} stuff.h awesome.h things.c Can I keep both? Multiple, simultaneous changes: Laptops? Colleagues? Problem 2: Edit Wars stuff.h awesome.h things.c stuff.h awesome.h things.c int main(){} int foo(){} ??? int main(){} void foo(){} stuff.h awesome.h things.c Can I keep both? Different files: Overwrite old version of each. (Trivial. A computer could do it without hints!) Same file, but lines dont overlap: Edit the file to incorporate each line modification. (Manually? Hmm) Same file, same lines: Conflicts! For each line, I choose what to do. (Can the computer help? Hmm..) Repository Solution: VCS VCS tool awesome.h things.c v8 awesome.h things.c v7 Version Control System Repository Solution: VCS awesome.h things.c VCS tool awesome.h things.c v8 awesome.h things.c v7 1: Get bits Version Control System Repository Solution: VCS stuff.h awesome.h things.c 2: Store changes stuff.h awesome.h things.c VCS tool v9 awesome.h things.c v8 awesome.h things.c v7 1: Get bits Version Control System Repository Solution: VCS stuff.h awesome.h things.c 2: Store changes stuff.h awesome.h things.c VCS tool awesome.h things.c v8 awesome.h things.c v7 1: Get bits Version Control System Why Git: Basic features are really useful, and advanced features if you want them Robustly retains your data, but can undo almost anything if needed Adaptable: you, the lab, MegaCorp v9 Git: Outline Using Git to record your project while you work How Git records your progress Using Git to organize your progress Sharing a project with other Git users Commit Primary unit for storing work Exists inside a repository A snapshot of what your projects files looked like when you made the commit Contains: author,address, timestamp, snapshot data, other stuff, unique hash of contents Commit History Unless an orphan, each commit descends (as the child) from at least one earlier commit (parent) Project history is all the projects commits in order Yes, history is a Directed Acyclic Graph whose nodes are commits. Hold that thought! Repository: 3 Areas stuff.h awesome.h things.c Commit HistoryStaging Area List of changes to the previous snapshot you will apply as the next snapshot Working Copy The file tree you see on your filesystem Commit History The snapshots you stored previously Repository: 3 Areas stuff.h awesome.h things.c Commit HistoryStaging Area List of changes to the previous snapshot you will apply as the next snapshot Working Copy The file tree you see on your filesystem Commit History The snapshots you stored previously Repository: 3 Areas stuff.h awesome.h things.c Commit HistoryStaging Area List of changes to the previous snapshot you will apply as the next snapshot Working Copy The file tree you see on your filesystem Commit History The snapshots you stored previously Repository: 3 Areas stuff.h awesome.h things.c Commit HistoryStaging Area List of changes to the previous snapshot you will apply as the next snapshot Working Copy Demo: Store a new project! Working Copy The file tree you see on your filesystem Commit History The snapshots you stored previously somefolder/ 1) Files are ready! (^>^) cd somefolder awesome.h things.c somefolder/ 0) (Need a repository first) Commit HistoryStaging Area somefolder/.git/ (^>^) git init # Create a new, empty repository in the current directory awesome.h things.c somefolder/ 1) (Files still untracked) Commit HistoryStaging Area somefolder/.git/ (^>^) git status awesome.h # untracked things.c # untracked # Git sees any file, but doesnt care about it until you say so.) awesome.h things.c somefolder/ 2) Add changes awesome.h things.c Commit HistoryStaging Area somefolder/.git/ (^>^) git add things.c awesome.h (^>^) # Changes are staged. # Git starts tracking a file the first time you add its changes! somefolder/ 2) (These are now tracked) awesome.h things.c Commit HistoryStaging Area somefolder/.git/ (^>^) git status new file: awesome.h new file: things.c somefolder/ 3) Commit staged changes awesome.h things.c Commit HistoryStaging Area somefolder/.git/ (^>^) git commit -m add initial functions (^>^) (^>^) # Always write a nice commit message! somefolder/ Commit terminology awesome.h things.c Commit HistoryStaging Area somefolder/.git/ Yes, this means you commit a commit. Sorry. somefolder/ Repeat: 1) Files are ready stuff.h awesome.h things.c Commit HistoryStaging Area somefolder/.git/ (^>^) $EDITOR things.c stuff.h somefolder/ Repeat: 1) (some tracked, some new) stuff.h awesome.h things.c Commit HistoryStaging Area somefolder/.git/ (^>^) git status stuff.h # untracked (The previous commit doesnt have this file.) things.c # modified (The previous commit has a version of this file.) somefolder/ Repeat: 2) Add changes stuff.h awesome.h things.c Commit HistoryStaging Area somefolder/.git/ (^>^) git add things.c stuff.h somefolder/ Repeat: Commit Stuff stuff.h awesome.h things.c Commit HistoryStaging Area somefolder/.git/ (^>^) git commit -m new parms in somefunction somefolder/ Check the log stuff.h awesome.h things.c Commit HistoryStaging Area somefolder/.git/ (^>^) git log add initial functions new parms in somefunction somefolder/ Good advice stuff.h awesome.h things.c Commit HistoryStaging Area somefolder/.git/ Use commit messages: Somebody in the future needs the help Separate your build artifacts: Use a build directory somefolder/build/ somefolder/ Good advice stuff.h awesome.h things.c Commit HistoryStaging Area somefolder/.git/ Use commit messages:Somebody in the future needs the help Separate your build artifacts:Use a build directory Avoid committing build artifacts:If you can get the project, you can build it! Release means you published binaries:Others can download from the website (or FTP site, etc.) somefolder/build/ Git: Outline Using Git to record your project while you work Commits How Git records your progress Using Git to organize your progress Sharing a project with other Git users The DAG Commit History History: The DAG grows as commits arrive. What about a new feature I want to keep separate? The DAG History: Work on a new feature, but keep it separated until its ready The DAG History: Work on a new feature, but keep it separated until its ready I drew another column, but this history is just a string! The DAG History: Work on a new feature, but keep it separated until its ready I drew another column, but this history is just a string! Work continues on the stable version: a commit can have more than one child Git: Outline Using Git to record your project while you work Commits How Git records your progress The DAG Using Git to organize your progress Sharing a project with other Git users The DAG History: Easy to find the history of any commit: follow links to visit every ancestor B A PC The DAG: Branches History: Easy to find the history of any commit: follow links to visit every ancestor Branches: We only need to store a single reference to identify each path; call it a branch ref (or just branch) B A PC feat42 The DAG: Branches History: Easy to find the history of any commit: follow links to visit every ancestor Branches: We only need to store a single reference to identify each path; call it a branch ref (or just branch) Git creates master branch by default, and stores commits there unless told otherwise B A PC master feat42 The DAG: Branches History: Easy to find the history of any commit: follow links to visit every ancestor Branches: We only need to store a single reference to identify each path; call it a branch ref (or just branch) Git creates master branch by default, and stores commits there unless told otherwise B A PC master feat42 Just a drawing convention! Only topology matters. The DAG: Branches Branches: Q: What are you working on right now? A: Current location is simply what the HEAD ref is pointing to Git appends your staged commit onto the DAG at the current branch, then moves the branch to that commit. B A PC master feat42 HEAD Branch details B A master P feat42 HEAD C Commits A, B, and P are on the feat42 branch, so feat42 usually means both of these identically: the ref named feat42 all the commits in the history of the ref named feat42 But if somebody says you can delete your feat42 branch, you know they mean the ref! Branch details B A master P (poof) HEAD C Deleting your feat42 branch is removing the branch ref! P is no longer in the history of ANY branch You can still access it, but Git will eventually garbage-collect such unreferenced commits (30 days by default) Branch demo B A OK, same example again. This time, note how some commands modify the branch refs. masterHEADfeat42 Branch demo B A (^>^) git branch # list the branches; * indicates current branch * master masterHEAD Branch demo B A (^>^) git branch feat42 # create the branch feat42 at current location masterHEADfeat42 Branch demo B A (^>^) git branch # notice we are still on master! feat42 * master masterHEADfeat42 Branch demo B A (^>^) git checkout feat42 (^>^) git branch * feat42 master HEAD feat42 Branch demo B A (^>^) $EDITOR newfeature.c (^>^) git add newfeature.c (^>^) git commit -m add function for feat42 master HEAD P feat42 Branch demo B A (^>^) git checkout master master P feat42 HEAD Branch demo B A (^>^) $EDITOR mainprog.c (^>^) git add mainprog.c (^>^) git commit -m fixed a bug master P feat42 HEAD C Problem: B A master P feat42 HEAD C Commit C contains a bugfix Commit P contains your new feature But your feature needs the bugfix, and Commit C is only in the history of master, not feat42 Problem: B A master P feat42 HEAD C Commit C contains a bugfix Commit P contains your new feature But your feature needs the bugfix, and Commit C is only in the history of master, not feat42 That is, you need the changes between B and C to be in the history of your feat42 branch: Merge B A master P HEAD C The most common technique is called merging: Snapshot P m will combine the image of C with the image of P P m will have more than one parent, making it a merge commit feat42 PmPm Merge demo B A master PC git merge Git will merge the branch you specify into your current branch (be careful!): feat42 (^>^) git checkout feat42 HEAD feat42 PmPm Merge demo B A master PC git merge Git will merge the branch you specify into your current branch (be careful!): feat42 (^>^) git checkout feat42 (^>^) git merge master HEAD PmPm Merge conflicts B A master PC Notice that Git must figure out how to merge two snapshots. Recall: feat42 HEAD Different files: Overwrite old version of each. (Trivial. Git does this automatically.) Same file, but lines dont overlap: Edit the file to incorporate each line modification. (Git is very good at figuring out how to do this.) Same file, same lines: Conflicts! For each line, I choose what to do. (Git identifies conflicting files, and marks any conflicts inside files.) PmPm Merge conflicts B A master PC feat42 HEAD Resolution: often interactively (meld, kdiff3, etc.) Simply part of life; not unique to Git. Not discussed further here. OK in small numbers, but pile up quickly. You can avoid many of them entirely! Conflicts! For each line, I choose what to do. (Git identifies conflicting files, and marks any conflicts inside files.) PmPm Merge conflicts B A PC branches diverge a lot between merges == a lot of merge conflicts at the next merge feat42 DQ RE F master feat42 is done. I bet this merge takes all day. I wish I saw those changed lines before I edited them! Merge conflicts B A PC branches diverge a little between merges == fewer merge conflicts at the next merge feat42 DPmPm Q QmQm E R master feat42 is done. Easy! Git combined most changes from master before I edited them! Merge conflicts B A PC branches diverge a little between merges == fewer merge conflicts at the next merge feat42 DPmPm Q QmQm E R feat42 is done. Easy! Git combined most changes from master before I edited them! Merging feat42 onto master will be easy! master Merge conflicts B A master PC branches diverge a little between merges == fewer merge conflicts at the next merge DPmPm Q QmQm E R Git only had to move the master ref forward from E to R to indicate feat42 is in its history. No merge commit! This is a fast-forward merge. feat42 feat42 is done. Easy! Git combined most changes from master before I edited them! Merging feat42 onto master will be easy! Merge conflicts B A PC branches diverge a little between merges == fewer merge conflicts at the next merge DPmPm Q QmQm E R Git only had to move the master ref forward from E to R to indicate feat42 is in its history. No merge commit! This is a fast-forward merge. Discipline counts: Many small commits! Separate changes logically! Merge often! feat42 master feat42 is done. Easy! Git combined most changes from master before I edited them! Merging feat42 onto master will be easy! Git: Outline Using Git to record your project while you work Commits How Git records your progress The DAG Using Git to organize your progress Branches Sharing a project with other Git users Sharing Repositories are identified by URIs, but each repository can name them for convenience You transfer commits between a repository and its remote repositories (remotes) master https://foo.org/bar.git /home/alice/ Sharing When you first access a project whose files are in a Git repository, you perform the following sequence: 1.create a new repo /home/alice/bar/ master https://foo.org/bar.git Sharing When you first access a project whose files are in a Git repository, you perform the following sequence: 1.create a new repo 2.add to it the remote you specified (naming it origin by convention) originhttps://foo.org/bar.git /home/alice/bar/ master https://foo.org/bar.git Sharing When you first access a project whose files are in a Git repository, you perform the following sequence: 1.create a new repo 2.add to it the remote you specified (naming it origin by convention) 3.copy origins branches and commits into your new repo (so you can easily keep your repo up-to-date) originhttps://foo.org/bar.git /home/alice/bar/ master https://foo.org/bar.git Remotes When you first access a project whose files are in a Git repository, you perform the following sequence: 1.create a new repo 2.add to it the remote you specified (naming it origin by convention) 3.copy origins branches and commits into your new repo (so you can easily keep your repo up-to-date) VERY common, so Git offers clone as a shortcut: originhttps://foo.org/bar.git https://foo.org/bar.git /home/alice/bar/ (^>^) git clone https://foo.org/bar.git master Remote tracking branches clone also sets up a branch ref which always points to the same commit in your repository as it does in the remote. This remote tracking branch is read-only: Git moves it for you based on where it was when you last checked. Here, your master branch is the tracking branch paired with origin/master. originhttps://foo.org/bar.git https://foo.org/bar.git /home/alice/bar/ master origin/master Notice that remote tracking branches are qualified by remote names! Syncing remotes Project members commit new commits to the master branch on the origin repository originhttps://foo.org/bar.git https://foo.org/bar.git /home/alice/bar/ master origin/master Syncing remotes Project members commit new commits to the master branch on the origin repository so you need to update your repository! This happens in 2 steps: originhttps://foo.org/bar.git https://foo.org/bar.git /home/alice/bar/ master origin/master Syncing remotes Project members commit new commits to the master branch on the origin repository so you need to update your repository! This happens in 2 steps: 1.fetch the state of tracked branches from the remote, along with any new commits originhttps://foo.org/bar.git https://foo.org/bar.git /home/alice/bar/ master origin/master Syncing remotes Project members commit new commits to the master branch on the origin repository so you need to update your repository! This happens in 2 steps: 1.fetch the state of tracked branches from the remote, along with any new commits 2.merge origin/master onto your master branch originhttps://foo.org/bar.git https://foo.org/bar.git /home/alice/bar/ master origin/master Syncing remotes Project members commit new commits to the master branch on the origin repository so you need to update your repository! This happens in 2 steps: 1.fetch the state of tracked branches from the remote, along with any new commits 2.merge origin/master onto your master branch VERY common, so Git offers pull as a shortcut for both steps: originhttps://foo.org/bar.git https://foo.org/bar.git /home/alice/bar/ (^>^) git pull origin master origin/master Syncing remotes Project members commit new commits to the master branch on the origin repository and that means you (or maybe Bob); heres how he did it: originhttps://foo.org/bar.git https://foo.org/bar.git /home/alice/bar/ master origin/master originhttps://foo.org/bar.git /home/bob/bar/ masterorigin/master Syncing remotes Project members commit new commits to the master branch on the origin repository and that means you (or maybe Bob); heres how he did it: 1. git pull origin # Just in case Alice put new commits there! Do this often! originhttps://foo.org/bar.git https://foo.org/bar.git /home/alice/bar/ master origin/master originhttps://foo.org/bar.git /home/bob/bar/ masterorigin/master Syncing remotes Project members commit new commits to the master branch on the origin repository and that means you (or maybe Bob); heres how he did it: 1. git pull origin # Just in case Alice put new commits there! Do this often! 2.place the new commits into the desired branch (master in this case); merge, direct commit, whatever originhttps://foo.org/bar.git https://foo.org/bar.git /home/alice/bar/ master origin/master originhttps://foo.org/bar.git /home/bob/bar/ master origin/master Syncing remotes Project members commit new commits to the master branch on the origin repository and that means you (or maybe Bob); heres how he did it: 1. git pull origin # Just in case Alice put new commits there! Do this often! 2.place the new commits into the desired branch (master in this case); merge, direct commit, whatever 3. git push origin # Naturally, this updates origin/master automatically originhttps://foo.org/bar.git https://foo.org/bar.git /home/alice/bar/ master origin/master originhttps://foo.org/bar.git /home/bob/bar/ master origin/master Project organization There are multiple copies of the repository. (Your laptop, your workstation, Bobs laptop) In principle, you can transfer commits from any repository to any other repository You and your team choose one to be the central repository by convention Github.com, Bitbucket.com, and similar services provide nice tools for organizing this. originhttps://foo.org/bar.git https://foo.org/bar.git /home/alice/bar/ master origin/master originhttps://foo.org/bar.git /home/bob/bar/ master origin/master Git: Outline Using Git to record your project while you work Commits How Git records your progress The DAG Using Git to organize your progress Branches Sharing a project with other Git users Remotes The remainder is elaboration and convenience. So How about now? xkcd.com/1597 If that doesn't fix it, git.txt contains the phone number of a friend of mine who understands git. Just wait through a few minutes of 'It's really pretty simple, just think of branches as...' and eventually you'll learn the commands that will fix everything. atlassian.com/git git-scm.com/book gitguys.com atlassian.com/git git-scm.com/book gitguys.com icts.uiowa.edu/confluencesee Version Control with Git events.uiowa.edu/event/git_workshopProf. Hans Johnson Michigan Room, IMU Monday, 1:30-3:00 Next: hands-on session in the lab Thanks! Questions?