├── .gitignore ├── LICENSE ├── README.md └── tutorials ├── add_commit_push_pull.md ├── branches.md ├── creating_and_cloning.md ├── pr.md ├── readme_license_gitignore.md ├── rebasing.md ├── removing_sensitive_files.md └── resolving_conflicts.md /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | .Ruserdata 5 | 6 | *.Rproj -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Wouter van Atteveldt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CCS-Amsterdam Git(hub) Workshop 2 | 3 | This repository contains a collection of howtos for dealing with git / github. 4 | 5 | For more information, the [git pro](https://git-scm.com/book/en/v2) book is an excellent and freely available resource. 6 | 7 | Preparation: 8 | 9 | * We assume that you have [git](https://github.com/git-guides/install-git) installed so that you can run commands in the terminal. There are graphical tools for working with git(hub), but using the command line tool helps understanding what you are doing, and will also prepare you for using git on a server without graphical interface and/or another computer without graphical tools installed. 10 | * Register your own [GitHub](https://github.com/) account 11 | 12 | # Howtos 13 | 14 | Basic Git(hub) usage 15 | 16 | - [Creating and cloning a repository](tutorials/creating_and_cloning.md) 17 | - [Adding, committing, pushing and pulling](tutorials/add_commit_push_pull.md) 18 | - [Resolving conflicts: merging changes](tutorials/resolving_conflicts.md) 19 | - [README, licence and .gitignore](tutorials/readme_license_gitignore.md) 20 | 21 | More advanced git(hub) usage 22 | 23 | - [Commits, parents, and rebasing](tutorials/rebasing.md) 24 | - [Working with branches](tutorials/branches.md) 25 | - [Forks and pull requests](tutorials/pr.md) 26 | - [Permanently removing sensitive files](tutorials/removing_sensitive_files.md) 27 | 28 | # Words of wisdom 29 | 30 | - Code should (almost) always be on github 31 | - A repository should (almost) always have a license 32 | - Pull when you start working 33 | - Commit early, commit often 34 | - Create a branch if you have 'work in progress' that you don't want to commit yet to the main line. And then commit and push that branch (early and often). 35 | -------------------------------------------------------------------------------- /tutorials/add_commit_push_pull.md: -------------------------------------------------------------------------------- 1 | 2 | # Working in your Git repository 3 | 4 | In the previous step you've created a `remote repository` on GitHub, and created a 5 | `local repository` by cloning it. Now we'll discuss the main commands for 6 | making changing in the `local repository`, and for interacting with the 7 | `remove repository`. We'll discuss 4 commands: 8 | 9 | * `git add`: add changes to the *staging area* 10 | * `git commit`: save the *staged* changes in the `local repository` 11 | * `git push`: push the committed changes to the `remote repository` 12 | * `git pull`: if changes have been committed to the `remote repository`, pull them to the `local repository`, and update your local files. 13 | 14 | ![Pushing and Pulling](https://i.imgur.com/qeagQD6.png) 15 | 16 | ## Making changes in your local repository 17 | 18 | When we make changes in our directory, we don't automatically update the local repository. 19 | That's a good thing: we don't want our version control system to store all the dumb 20 | stuff we tried in writing our code. We want to be able to tell Git when we're ready to *commit*. 21 | For this, we need the `git add` and `git commit` commands. 22 | 23 | The *commit* is the part where we actually save our changes to the repository. 24 | This part should make sense: you've made changes to your directory, and now 25 | you want to store them safely in your version control system. 26 | However, before you can do this, Git first requires you to specify which changes you 27 | actually want to commit. You'll later see why this makes sense. For now, just consider that sometimes you 28 | put stuff in your directory that you don't want to add to the public repository (e.g., private data). 29 | 30 | We specify which changes to make by *adding* them to the *staging area*. 31 | This is easiest to just show. Open your terminal and navigate to your local repository. 32 | Let's first run `git status` to see what's up. 33 | 34 | ``` 35 | git status 36 | ``` 37 | 38 | If you haven't yet made any changes to your directory, this should tell you that there's 39 | "nothing to commit, working tree clean". So now let's actually make some changes. 40 | We're going to create a simple text file called `hello_world.txt`, that just contains the text 41 | "hi". It doesn't matter how you create this file, but for this example we'll do this from the 42 | command line (just because we can). 43 | 44 | ``` 45 | echo "hi" > hello_world.txt 46 | ``` 47 | 48 | You can verify that this worked (`dir` on Windows, `ls` on Mac or Linux) 49 | Now, if you run `git status` again, you should see something like: 50 | 51 | ``` 52 | On branch main 53 | Your branch is up to date with 'origin/main'. 54 | 55 | Untracked files: 56 | (use "git add ..." to include in what will be committed) 57 | hello_world.txt 58 | 59 | nothing added to commit but untracked files present (use "git add" to track) 60 | ``` 61 | 62 | It tells you that there's a file named hello_world.txt that's untracked (perhaps 63 | it's even colored red in your terminal, to illustrate the drama). It also 64 | nicely tells you that you can use "git add" to track the file. 65 | In the next step, we're going to do this, and specifically we're going to run: 66 | 67 | ``` 68 | git add . 69 | ``` 70 | 71 | Note that we put a dot after add. After `git add` you can specify which specific files you want to add. 72 | The dot here is convenient shorthand for saying `add everything`. 73 | 74 | So all the untracked changes have now been 75 | *added* to the *staging area*. If you run `git status` again, it should now tell you so, 76 | and color the changed files in a comforting green color. 77 | 78 | Now that the stage is set, we can *commit*. For this command we'll use an additional argument 79 | to add a message to our commit. 80 | 81 | ``` 82 | git commit -m "I created a file called hello_world.txt" 83 | ``` 84 | 85 | If you run this, you get some minor feedback on what you changed (how many files, how many insertions). 86 | The changes are now committed! 87 | The `-m "blablabla"` part of the command basically just adds a brief message (m) where you should 88 | describe what changes you made. It's important to make clear descriptions (but in practice most people 89 | don't, and yes, off course there is an [xkcd](https://xkcd.com/1296/) about that). 90 | 91 | And that's it! Now we're ready to push our changes to the `remote repository`. 92 | 93 | ## Pushing changes from local to remote 94 | 95 | You've now committed some changes to your `local repository` (this can be one commit, 96 | but also several). You figured it's about time to share your progress with your team, 97 | so the next step is to `push` your changes to the `remote repository`. 98 | 99 | Let's first take a look again at `git status`. If you've committed something, this should 100 | now tell you that `Your branch is ahead of 'origin/main' by x commits`. We can now push 101 | these local commits to publish them. 102 | 103 | ``` 104 | git push 105 | ``` 106 | 107 | This will probably ask you for your username and password. There are ways to prevent this, 108 | and when you start using GitHub regularly you'll want this, but for now we'll keep it simple. 109 | In any case, if all went well, you've now pushed the commits. 110 | If so, you can open your GitHub repository in your web browser to see that your file has indeed 111 | been added. 112 | Also, if you again run `git status`, you should see that you're now back to a clean branch. 113 | 114 | 115 | ## The add, commit and push mantra 116 | 117 | We've spent quite some time discussing `add`, `commit` and `push`. 118 | But although these are three separate commands, you should get by just fine if you 119 | think of them simply as a single mantra that you need to recite whenever you want to push your changes to GitHub. 120 | 121 | ``` 122 | git add . 123 | git commit -m "short description of what changes you made" 124 | git push 125 | ``` 126 | 127 | Sure, there are cases where it might be better to make several commits, 128 | and then pushing everything in one go. But for smaller projects, and certainly 129 | for individual projects, you can just think of `add-commit-push` as a single operation. 130 | 131 | 132 | # Pulling changes from the remote repository 133 | 134 | Now you know how to make changes to the remote repository. 135 | If you are working just by yourself, this is enough to keep your project going. 136 | But if you are working together with others **who also push changes**, it's important 137 | that **you also pull changes**. 138 | 139 | Conveniently, you can just pull to see whether the remote repository has been updated. 140 | 141 | ``` 142 | git pull 143 | ``` 144 | 145 | This should tell you that you're `Already up to date`. Makes sense, since you're 146 | the only one working on this repository. But we can actually pretend that someone 147 | made some changes, because you are allowed to change files directly on GitHub. 148 | 149 | Visit your GitHub repository from your web browser, and click on the `.txt` file that you created before. 150 | Now to the top-right of the file, you should see the `Raw` and `Blame` buttons, and next to it a pencil. 151 | Click on the pencil to enter edit mode. Now just type some stuff in the file. 152 | At the bottom of the page, you can now *commit* this change. 153 | 154 | Now the `remote repository` has changed, but your `local repository` hasn't. 155 | Specifically, your `local repository` is now *behind* by 1 commit. 156 | Now let's run pull again. 157 | 158 | ``` 159 | git pull 160 | ``` 161 | 162 | This should now show you that it downloaded the changes, and should provide a brief 163 | summary of which files specifically have changed, and how much. 164 | Most importantly, your `local repository` is now again up to date, and if you 165 | run `git pull` again it will tell you as much. 166 | 167 | ## Good Workflow Habits 168 | 169 | + **Pull before you start working**. If you make changes, you want them to be based on the most recent version of the project. So, always `git pull` before you start working on something (and generally do a quick `git status` even before that so you can see if you accidentally forgot to commit something) 170 | + **Commit early, commit often**. Having lots of relatively small commits is better than one big commit after a day (or more) of work. Ideally, whenever you make a standalone change (fix some issue, rewrite or reorder some paragraph(s)), commit it with a message stating why you made those changes. This allows others (and your future you) to understand why you did certain things. If you wait a long time between commits you often don't really remember why you did something, and there is a bigger chance that someone else changed something in the meantime. So, commit and push your changes as often as possible (and we will later learn about [branches](branches.md) that allow you to commit changes without interfering with other users) 171 | 172 | ## Exercises 173 | 174 | 1. Make sure you have a GitHub repository for testing and you cloned it on your local computer. 175 | 2. Edit the README.md file on your computer 176 | 3. Check `git status`. Do you understand the output? 177 | 4. Stage your change using `git add README.md`, and check `git status`. Do you understand the output? 178 | 5. Commit your change using `git commit -m "Edited the readme"`, and check `git status`. Do you understand the output? 179 | 6. Push your change using `git push`, and check `git status`. Do you understand the output? 180 | 7. On Github, refresh and see that your change is now visible. Within GitHub, edit the file and make another change. 181 | 8. On your local computer, check `git status`. Can you see the change from GitHub? Why not? 182 | 9. Update your local repository with `git pull`. Do you understand the output? 183 | -------------------------------------------------------------------------------- /tutorials/branches.md: -------------------------------------------------------------------------------- 1 | # Working with Branches 2 | 3 | (See chapter 3 of the [git pro book](https://git-scm.com/book/en/v2/Git-Branching-Branches-in-a-Nutshell) for more details) 4 | 5 | When looking at github, you have probably encountered the name *main* in multiple places. 6 | This is the (default) name of the default (main) branch. 7 | 8 | Essentially, a branch is simply a named reference to a particular commit. 9 | Since a commit (with all its (grand)parents) identifies a particular state (snapshot) of the repository, 10 | a branch can also be seen as a particular state or snapshot of the repository. 11 | So, if you have two branches, they are essentially two different versions of the repository, 12 | usually sharing part of the commit history, but diverging at some point. 13 | 14 | [Note that main used to be called *master*, but as part of a push to remove references to master/slave relations from the computer science jargon, it was renamed to main on github. 15 | If you create a repository with `git init` rather than on github, the default is still *master*, at least on git 2.25.1] 16 | 17 | ## Creating a branch 18 | 19 | You can use `git branch mybranch` to create a new branch called mybranch. 20 | Then, you can use `git checkout mybranch` to activate that branch (or more formally, set your *head* to that branch). 21 | As a shorthand, you can use `git checkout -b mybranch` to create and activate a new branch. 22 | 23 | Now, if you create a new commit, your branch will point to that new commit, but the old *main* will still point to the previous commit. 24 | If you try to push this commit, you will get a somewhat cryptic message that *the current branch testbranch has no upstream branch*. 25 | What this means is that git doesn't know where to push your changes to. 26 | Less cryptically, it tells you to run `git push --set-upstream origin mybranch` in order to fix this: 27 | Push your changes, setting the upstream for your branch to a (new) branch mybranch on *origin* - the name for the place you cloned the repository from (i.e. Github; you can check this with `git remote -v`). 28 | 29 | ![creating a branch](https://i.imgur.com/1saHbZD.png) 30 | 31 | Exercise: 32 | 33 | 1. Create and checkout a new branch on your computer 34 | 2. Change a file, commit it, and push the change 35 | 3. Go to github. You can now select the branch you created in the top left corner. It will tell you that this branch is 1 commit 'ahead' of master. 36 | 4. Go to insights->Network. You will see that your branch diverges from the main branch, and both now exist side-by-side 37 | 38 | ## When to use branches? 39 | 40 | Branches are very useful in at least three circumstances: 41 | 42 | 1. You are working on some changes that you are still unsure about or don't want to commit to the main line, 43 | for example because your change breaks everything so others will have trouble working with the code, 44 | or because you are rewriting a big section of a document and the text doesn't make sense until your change is done. 45 | In this case, you can create a branch to still be able to commit your changes, without disturbing others working on the same repository. 46 | 2. Alone or together with others, you are working on a bigger feature or change request. If you create a branch for this, 47 | you can collaborate on the feature (by both working in the same branch) without disturbing the main line, 48 | and it is also clear that the commits used to create the feature or fix the bug all belong together. 49 | 3. You have a stable version of your tool that you wish to maintain, while also continuing to work on a new version. 50 | You can create a separate branch for the released version (or for the development version - either works), 51 | and have separate commits to the stable and development version. 52 | 53 | ## Merging branches 54 | 55 | In each of the use cases, at some point you probably want to merge branches again. For example, if you finished your rewrite, feature, or bugfix, you want to apply the changes back to main. 56 | The way to do this is to activate the repository you want to merge the changes *into*, so `git checkout main`. 57 | Now, you can ask git to merge the changes from your branch by doing `git merge mybranch`. 58 | If there are not changes to *main* in the meantime, this will "fast forward" main to include the commits from *mybranch*, and both branches will point to the same commit. More likely, the main branch will also be changed in the meantime, and git will create a new merge commit that has both the latest commit from main and from mybranch as parent. 59 | 60 | This is illustrated below. C1 was the last commit in the repository before the branch was created. 61 | Then, C2 was created on the branch. Merging directly after committing C2 allows `git merge mybranch` to *fast forward* the main branch, since mybranch is stricly ahead of main. 62 | If C3 is committed on the main branch in the meantime, however, you cannot fast forward as the branches have diverges. 63 | Thus, `git merge mybranch` will create a new merge commit (M), and point the main branch to this new commit. 64 | The mybranch branch will still point to C2, and now be strictly behind the main branch. 65 | 66 | ![Merging branches](https://i.imgur.com/PaMfjb9.png) 67 | 68 | As usual, if commits from both branches changed the same parts of files, there will be a merge conflict that you need to resolve manually, and then `git add` the resolved files and `git commit` the merge. 69 | 70 | In any case, after merging the branches you can delete the old branch if you no longer need to work on it. 71 | This can be done locally with `git branch -d mybranch`. 72 | To delete the branch on github, it's easiest to go to github, click on the *N branches* icon, and use the trashcan icon to delete it. 73 | 74 | ## Pull requests 75 | 76 | When you have a branch on github, you can automatically create a *pull request* for the branch. 77 | A pull request is essentially a request to have the branch merged. 78 | This is quite a nice feature by itself as it allows you to automatically merge the branch without having to use the commands above. 79 | There is even a built-in editor to resolve and merge conflicts. Kids these days really do have it easy... 80 | 81 | However, this feature really shines when you want to discuss whether the changes are a good idea. 82 | For example, maybe you are the second author or otherwise not in charge of a project, 83 | and your branch represents a significant rewrite or change. 84 | In that case, you can create a 'pull request', that can be seen as a polite question to the other collaborator or first author 85 | whether they agree with your changes. 86 | They can easily review the changes, merge them if required, and otherwise reject the request. 87 | 88 | In a pull request, you will also see if it can be merged without conflicts. 89 | In the 'second author' scenario, you probably want to present changes that can be merged easily. 90 | Thus, if there are any conflicting changes in the main branch, you want to resolve them in your branch before discussing the pull request. 91 | To do this, `git checkout main` to activate the main branch and `git pull` any changes. Now, switch back to your branch (`git checkout mybranch`), 92 | and do `git merge main` to merge all commits in main into this branch. 93 | This will prompt you to resolve any conflicts, and create a new merge commit in your branch that has both your last commits and the last commit from main as a parent. 94 | If you then `git push`, the new commit is automatically added to the pull request (since a PR references the branch, not the commit), 95 | and the request should now merge without problems. 96 | 97 | 98 | ## Exercise 99 | 100 | Suppose you are making a big change, and you want to make this change in a separate branch: 101 | 102 | 1. Create a new branch 'mybranch' locally, make a change, commit it, make another change, and commit that as well. 103 | 2. Run `git log`. Where do `HEAD`, `mybranch`, `master`, and `origin/master` point to? Is there an `origin/mybranch`? 104 | 3. Push your new branch with `--set-upstream`. Check `git log` again. What changed? Why? 105 | 4. Go to github and look around in your new branch. 106 | 5. On github, in the main branch, edit a separate file. 107 | 6. On your computer, do `git pull`. Nothing will change, because your branch has not changed on github. 108 | 7. Checkout the main branch and `git pull`. The change on github is now pulled to your local *main* branch. 109 | 8. Merge your branch with `git merge mybranch`. Check the `git log`. Does it all make sense? 110 | 9. Push your change and check the github network (in insights). Does this make sense? 111 | 112 | Now, repeat the above exercise, but in step 5 change the same file that you edit in the branch, and fix the resulting merge conflict. 113 | 114 | Finally, repeat this exercise, but using a pull request to merge the change after step 5. 115 | -------------------------------------------------------------------------------- /tutorials/creating_and_cloning.md: -------------------------------------------------------------------------------- 1 | # What are Git and GitHub? 2 | 3 | Roughly speaking, there are two levels of understanding Git. 4 | The first is to know a handful of commands that allow you to effectively use 5 | Git in your own projects. The second level is to actually understand the elegant 6 | Git *branching* model and using it to it's full potential. 7 | 8 | In practice, even many people that use Git effectively and on a regular basis 9 | hardly get beyond that first stage. And off course there is an [xkcd](https://www.xkcd.com) comic to illustrate this point: 10 | 11 |
12 | 13 | In this workshop we first and foremost focus on the first level of understanding. 14 | We do address some of the more advanced features, but the primary goal is to show you 15 | why Git is useful and how you can use it. Let's start with a simple description of what Git is, and how it's related to GitHub. 16 | 17 | ## Git is a version control system 18 | Git is a system for managing repositories. 19 | A Git repository is a directory that contains all the files in a project, 20 | including the complete history of revisions (called *commits*). 21 | This allows you to restore the content of the directory to a previous version. 22 | 23 | Now, version control is nice, but that's probably not the reason you joined 24 | this workshop. Stuff like Dropbox also has some nice version control, and doesn't 25 | require a workshop. However, if you ever used this type of software for real-time 26 | collaboration, you get why it wouldn't really work with programming tasks. Perhaps 27 | you've even lived the hell of conflicted copies, or lost a directory that someone 28 | accidentally deleted. 29 | 30 | What you'd really want is something like a version control 31 | system designed for this type of collaboration. 32 | The big difference between Git and something like Dropbox is that git version control is *explicit*: 33 | as a user, you explicitly create and name a new version (a *commit*), and you control the process of merging with other people's changes. 34 | That is a bit more work than the 'magic' versioning of Dropbox, but it means that you never accidentally overwrite changes or create conflicting versions. 35 | 36 | ## Git is a *distributed* version control system 37 | Git is designed to facilitate collaboration. 38 | Imagine several programmers working together on a project. 39 | To develop and test code they need to have local copies of the project, 40 | but this makes it very difficult (and cumbersome) to ensure that the different 41 | copies of the projects stay synchronized. 42 | A distributed version control system such as Git makes this as painless and efficient 43 | as possible. 44 | 45 | Rather than discuss how this works right now, it's much easier to show it, so 46 | let's quickly move on. 47 | 48 | ## GitHub is a hub for Git repositories 49 | People sometimes mistake Git and GitHub for being the same thing. 50 | GitHub is a hosting service for Git repositories. 51 | It is literally a hub, that connects different users working 52 | on the same repository ([as visualized here](https://phpenthusiast.com/blog/the-essentials-of-git-and-github-for-web-developers#local_vs_remote_repo)). 53 | 54 | If a repository is hosted (on GitHub), we call this the `remote repository` (or central repository). 55 | The repositories of the different users on their own local systems are called `local respository`. 56 | Each local repository is directly connected to the remote repository, so if everyone manages to stay in sync with the remote repository, everyone stays in sync. 57 | One of the most important topics of this workshop is how to manage this. 58 | 59 | 60 | # Setting up Git and GitHub 61 | 62 | For this workshop you should have [git](https://github.com/git-guides/install-git) installed, and registered a [GitHub](https://github.com/) account. If you haven't done this already, please do it now. 63 | 64 | ## Username and email addres 65 | 66 | Now, there are some basic settings that you need to look into. 67 | Most importantly, you need to specify your git email address and name (depending 68 | on how you installed git, this might already have been asked). 69 | What's important here is that your email address is **the same address that you 70 | use on GitHub**. 71 | 72 | Let's actually do this from the terminal. As a reminder, on Windows you can go to start (or press the windows key) and type cmd to find the command prompt. On Mac, you can press command + spacebar (or apple-key + spacebar) and type terminal. On Ubuntu and some other Linux distributions it's `ctrl+alt+t`. 73 | 74 | In your terminal, first just type git and hit enter, to see if you installed it properly. 75 | 76 | ``` 77 | git 78 | ``` 79 | 80 | If this gives you an overview of important git commands, you know it's installed properly. 81 | Now we can set your username and email. For this run the following two commands (don't forget 82 | to set your own name and email address) 83 | 84 | ``` 85 | git config --global user.name "your name" 86 | git config --global user.email "you@something.com" 87 | ``` 88 | 89 | You can now also check whether it worked: 90 | 91 | ``` 92 | git config --global user.name 93 | git config --global user.email 94 | ``` 95 | 96 | 97 | ## Setting up GitHub authentication 98 | 99 | When at some point (in about 15 minutes) you're pushing your first commits to 100 | GitHub, you'll naturally be required to authenticate. It used to be the case 101 | that you can just give your username and password, but [the times they are a-changing](https://github.blog/2020-12-15-token-authentication-requirements-for-git-operations/#what-you-need-to-do-today). 102 | For you now you can still do this (the dates mentioned in the link have been postponed), but you might get a warning that this is 'deprecated', 103 | and will no longer be possible from August 13, 2021. For more details 104 | 105 | If you're completely new to Git, you might want to ignore this issue for now and continue 106 | with the workshop. But at some point you will have to deal with it, and then there 107 | are two options. 108 | 109 | * The seemingly easiest option is to get a [personal access token](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token). You can then just use this token instead of your password (i.e. literally, give this token when they ask for you password). Chances are good that you only need to do this once (or every once in a while) if your systems uses a password manager. 110 | * The better solution is to use SSH authentication. You set this up once for every computer that you use, and you're good to go. GitHub provides clear instructions for [Windows, Mac and Linux](https://docs.github.com/en/github/authenticating-to-github/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent#generating-a-new-ssh-key). One thing to remember though, is that with SSH authentication cloning a repository (as shown below) works slightly differently. Instead of `git clone https://github.com/user/repository`, it becomes `git clone git@github.com:user/repository`. 111 | 112 | # Creating a repository 113 | 114 | To work on an existing project, you *clone* it from GitHub. 115 | Similarly, the easiest way to create a new git repository is to create it on the GitHub webiste, and then clone it to your local computer. 116 | 117 | Note that you can also create a git repository locally (with `git init`) and later add it to GitHub (or even work without GitHub altogether), 118 | but it's easier to just start working from GitHub rightaway. 119 | 120 | ## git clone: creating a local clone of a remote repository 121 | 122 | If a git repository already exists, and is hosted on a platform such as GitHub, 123 | you can create a local `clone` of this repository using the `git clone` command. 124 | 125 | This workshop itself has it's own [GitHub repository](https://github.com/vanatteveldt/github-workshop). 126 | You can clone this repository to your local system with the `git clone` command, 127 | followed by the url. 128 | Open your terminal and navigate to a directory in which you would like to place 129 | the clone. Now run the following code. 130 | 131 | ``` 132 | git clone https://github.com/vanatteveldt/github-workshop.git 133 | ``` 134 | 135 | Now that you have created the directory, you can navigate to it. 136 | 137 | ``` 138 | cd github-workshop 139 | ``` 140 | 141 | You can verify that this directory actually holds a copy of the repository by listing 142 | the files. On Windows the command is `$ dir`, and on Mac and Linux it's `$ ls`. 143 | 144 | 145 | So what can you do with this local repository? Well, in addition to having the files, 146 | you also have the complete version history, and you can revert back to previous versions. 147 | You can also at any time check and pull new updates. 148 | 149 | What you can't do, is make changes to the remote repository, because you're not 150 | a registered collaborator. Basically, you have read access, but no write access. 151 | Still, you are allowed to make changes, and you can ask the maintainers of the 152 | repository whether they want to adopt your changes. So without being an official collaborator 153 | you can still be a nice person who helps. But more on that later when we get to `pull requests`. 154 | 155 | 156 | # Excercise: creating your own repository via Github 157 | 158 | *Please make sure to actually complete this exorcise, because you'll need the repository created 159 | here in the next steps of the workshop.* 160 | 161 | To create a new repository on GitHub, go to you profile page, and open the `Repositories` 162 | tab. Here click on the bright green button that says `New`. Pick a name for your pet 163 | repo, and optionally add a description. You can leave the public/private setting on public (i.e. anyone can see it). 164 | Check all the checkboxes for `README`, `.gitignore` and `licence`. 165 | For `.gitignore` select the R template (we won't use R, this is just for illustration). 166 | Set the license to MIT. 167 | 168 | Finish creating the repository. You should now see you own GitHub repo with only the files 169 | .gitignore, LICENCE and README.md. The next step is to clone this repository. 170 | Copy the URL of your fresh new repository, and execute the `git clone` command (don't 171 | forget to navigate to a directory in which you want to put it). 172 | 173 | ``` 174 | git clone https://github.com/[your github profile]/[your repository].git 175 | ``` 176 | 177 | -------------------------------------------------------------------------------- /tutorials/pr.md: -------------------------------------------------------------------------------- 1 | # Forks and Pull Requests 2 | 3 | In the [tutorial on branches](braches.md), you learned how you can use branches to make changes in a different 'snapshot' of the repository, and merge the changes back manually or using a pull request. 4 | That is a great work flow for collaborating within a project. 5 | 6 | However, in the world of open source / open science you sometimes want to make changes to code from another team or project, 7 | and generally you will not have the right to push changes to the repository the code is in. 8 | 9 | For example, if another group created a tool that is really useful, but it needs some minor changes to work for your task or there is a minor bug that is, well, bugging you. 10 | Of course, you can politely ask the other group to make those changes or fix the bug, but you can also do it yourself! 11 | 12 | # Creating a fork 13 | 14 | The first step in changing someone else's code is to **fork** it. 15 | You can fork a repository using the fork icon in the top right on github. This creates a complete copy of the repository (including the full commit history) 16 | in your own space (i.e. github.com/yourname/therepository). 17 | From there, you can clone, edit, commit and push it as normal, and create branches, issues, and collaborate on it. 18 | For all purposes, this is now a complete and independent copy of the project, owned (in the technical sense) by you. 19 | 20 | ## Aside: Licenses and copyright 21 | 22 | Before forking, you should always check the license to make sure that it allows you copy and edit it. 23 | For open source licences like MIT or GPL and creative commons licenses except for CC-ND, this is always allowed as it is the core of open source that you can make changes to a program. 24 | However, note that with GPL or CC-SA you are legally obliged to also license your code under the same license, and with CC-NC you are not allowed to profit commercially from your copy. 25 | 26 | If there is no license file, you should probably contact the original author and gently prod them to [include an explicit license](https://docs.github.com/en/github/building-a-strong-community/adding-a-license-to-a-repository). 27 | 28 | # Creating a pull request 29 | 30 | If you want to add a specific feature to or fix a bug in someone else's project, you of course want to share the changes back with them. 31 | This is not only good citizenship, it also means that you can switch back to using the 'official' version of the tool, 32 | and not continue using your fork that will diverge or become outdated as development continues on the original project. 33 | 34 | Creating a pull request is easy: if your fork is ahead of the original github will prompt you to 'create a pull request' on the front page of your repository. 35 | The original owner will automatically be notified of this request, and they can decide to merge it or ask you to make specific changes. 36 | Pull request can also include comments to facilitate discussion (e.g. asking for clarification or specific changes before merging the change). 37 | 38 | Note that if you intend to make a specific change or bug fix, it is almost always a smart idea to create a new local branch for it, 39 | just as if you would make a major change locally. This keeps commits in your branch distinguishable from possible new commits to the main branch, 40 | and makes it easier to make two separate pull request for separate changes. 41 | 42 | ## Exercise 43 | 44 | 1. Ask your (virtual) neighbour for a link to their test repository, and fork it on github. 45 | 2. Create and checkout a local branch 46 | 3. Change one of "their" files, commit, and push. 47 | 4. Create a pull request of your change, and ask your neighbour to merge the request. 48 | 49 | Alternatively, if you see any typo's or mistakes in this repository, fork it, fix it, and create a pull request. 50 | 51 | # Updating your fork 52 | 53 | The key feature of a fork is of course that both groups can now work independently on separate copies of the code. 54 | This, however, also means that the two forks can diverge. 55 | It is quite likely that while you were making your new feature or bugfix, the original project also continued developing. 56 | 57 | So, if you want to continue working with your fork, you want to pull the changes from the original project into your fork, 58 | The easiest way to do this is to go to github and view your main branch. It should tell you that you are N commits behind the original, 59 | and allow you to create a pull request, that you can then directly merge yourself. 60 | 61 | Note that you can also make these changes yourself 62 | 63 | 1. Switch to your main branch 64 | 1. Add the original project as a second 'upstream' remote: `git remote add upstram git@github.com:originalowner/repository` 65 | 2. Fetch the changes from the remote repository: `git fetch upsteam` 66 | 3. Merge the remote changes into your local main branch: `git pull upsteam main` 67 | 4. If desired, push the changes to github: `git push` 68 | 69 | After bringing your local main branch up to date, you can of course merge these changes into any feature or bugfix branch if desired (for example, if your pull request fails to merge), 70 | by switching to your repository and using `git merge main` as before. 71 | 72 | ## Exercise 73 | 74 | 1. On your forked repository, create and activate a new branch, change a file, commit, and push. 75 | 2. Ask your neighbour to make a change to the same line in the same file. 76 | 3. Try to make a pull request on the github page of your fork. It should tell you that there is a merge conflict. 77 | 4. Update your 'main' repository (either using a pull request or by adding a second remote) 78 | 5. Merge your neighbour's changes into your branch, resolve the conflict, and push the changes. 79 | 6. Make a pull request on the github page of your fork (or check the PR you make in step 3 if you didn't cancel it). It should now merge without problem. 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /tutorials/readme_license_gitignore.md: -------------------------------------------------------------------------------- 1 | # README, licence and .gitignore 2 | 3 | When you created the GitHub repository, we asked you to check all the boxes for adding 4 | the README, license and .gitignore files. Here we'll briefly elaborate on why these 5 | are useful. 6 | 7 | 8 | ## README.md 9 | 10 | You'll probably know the idea of a readme file already. But good to know is that 11 | on GitHub, the readme file is also displayed on the main page of your repository. 12 | So here you can add anything you want to say to your audience. The format is a [markdown](https://github.com/adam-p/markdown-here/wiki/Markdown-Cheatsheet) file. 13 | 14 | 15 | ## licence 16 | 17 | It can be useful for possible users of your data/code to know something about the 18 | legal status. Perhaps most importantly, to what extent can they just copy and use it? 19 | There are some standard templates for licences, and on GitHub you can choose which licence 20 | you want to include. [This here](https://choosealicense.com/) is a good simple guide for open source. 21 | 22 | 23 | ## .gitignore 24 | 25 | A .gitignore file is a file in your repository that specifies which files git should ignore (what's in a name). 26 | For example, if your repository contains an R project, there are certain files that 27 | you often don't want to share. 28 | 29 | Conveniently, GitHub has templates for certain types of content. 30 | When you created the GitHub repository, we asked you to select the [R template](https://github.com/github/gitignore/blob/master/R.gitignore). 31 | If you now open this file (or follow the link), you'll see a list of files, and patterns for matching files, 32 | that are ignored. 33 | 34 | You can also add your own patterns. For instance, you might want to share your code and results 35 | on github, but not your raw data. It is then convenient to still keep the raw data in your 36 | local directory, but NOT commit it to the repository. This can be achieved by adding the name 37 | of the raw data file (or a pattern for matching multiple files) to .gitignore. 38 | 39 | -------------------------------------------------------------------------------- /tutorials/rebasing.md: -------------------------------------------------------------------------------- 1 | # Commits, parents, and rebasing 2 | 3 | To understand more of the underlying mechanism behind git(hub), it's important to realize what a commit really is: 4 | 5 | + A git repository can be seen as a sequence of *commits* 6 | + Each commit consists of a list of changes to files (*diffs*) and at least one *parent* commit. 7 | + Each commit is identified by a unique 'hash' 8 | + This hash is calculated from both the changes and parent, so the same changes with a different parent give a different hash (and hence is treated as a different commit) 9 | + The state of the files in the repository and completely determined by the 'sum' of the last commit and all its (grand)parents. 10 | 11 | This information is displayed directly on github when you click on a commit in the history. 12 | For example [this commit](https://github.com/vanatteveldt/testrepo/commit/27b8900a27b8a95fd390a5cbcf2c4835955a11c3) has the hash `27...c3`, parent `ba10cdb`, and changed a single file. 13 | You can also browse the code at that commit by clicking the 'browse files' button. 14 | 15 | ## Conflicts when pushing 16 | 17 | Let's assume that you have a repository, with the latest commit being `C1`. Now, you make some changes to a file, and commit them, creating commit C2. 18 | However, in the meantime someone else committed a change to te repository, creating commit C3. 19 | If you try to push your change, it will be *rejected* even if the other commit changes completely different files than you did. 20 | 21 | The reason for this has to do with the parents. The commit you want to push has C1 as parent, while the current remote head commit is C3. 22 | Simply put, you can only push commits that are based (parented) on the head commit that you are trying to push to. 23 | 24 | ![merge conflict](https://i.imgur.com/2iGX0bw.png) 25 | 26 | ## Merging and rebasing 27 | 28 | So, you need to fix this situation in order to push your work. There are two options here, both involving `pull`ing the latest changes from the remote repository before pushing. 29 | 30 | 1. *Rebasing* The instructions we gave you earlier is to use `git pull --rebase` in case of a conflict like this. Rebasing means that git temporarily stashes your commit (C2), and pulls in the remote changes, bringing your local state to C3. Then, it 'replays' your changes on top of C3, creating a commit (C2b) with the same changes as C2, but with C3 as parent. Note that since the parent is part of the hash, this is treated as a different commit. 31 | 2. *Merging* The second option is to just use `git pull`. This will automatically try to merge your changes by creating a third commit (M), that has both commits C2 and C3 as a parent. 32 | 33 | In both cases, after doing the pull your local head commit is not strictly ahead of the remote head, so you are allowed to push the changes. 34 | 35 | ![rebase or merge](https://i.imgur.com/2qOxHV8.png) 36 | 37 | As before, if there are conflicts (i.e. the same part of a file was edited in both commits), you will need to manually solve these conflicts as normal and use 38 | `git add ` to mark the conflict as resolved. In the case of rebase, you then use `git rebase --continue`, which will fold the new changes into the rebased commit (C2b), 39 | and then apply more commits if needed. In the case of merge, you then use `git commit` to create the new 'merge commit' M. 40 | 41 | When to use rebase or merge? Both get the job done, so it doesn't matter a lot. Rebasing gives a cleaner history, as you don't clutter the history with empty merge commits. 42 | So, for most cases we would advice using `git pull --rebase`. For bigger changes, when you expect real conflicts, or when you are merging two branches, it is better to use merging, as the explicit commit is more informative. 43 | 44 | ## Exercises 45 | 46 | Rebasing: 47 | 48 | 1. Have a look at the commits in your history, and browse the repository at an earlier version 49 | 2. Create a new file locally, and at the same time edit the README file of your repository. Commit your local changes. 50 | 3. Locally, run `git log`. Note down the hash of your commit. 51 | 3. Try to push. Read and understand the resulting error message. 52 | 3. Use `git commit --rebase` to solve the conflict, and push your changes. Read and understand the messages. 53 | 3. Locally, run `git log` (or check the history on github). See that your old commit is there, but with a new hash (and parent). 54 | 4. Go to github and navigate to *insights*->*Network*. Observe that both commits are a straight line (your commit follows directly on the conflicting commit) 55 | 56 | 57 | Merging: 58 | 59 | 2. Create a new file locally, and at the same time edit the README file of your repository. Commit your local changes. 60 | 3. Locally, run `git log`. Note down the hash of your commit. 61 | 3. Try to push. Read and understand the resulting error message. 62 | 3. Use `git commit` to solve the conflict using merge, and push your changes. Read and understand the messages. 63 | 3. Locally, run `git log` (or check the history on github). See that your old commit is there with a same hash, and a new merge commit was created. 64 | 4. Go to github and navigate to *insights*->*Network*. Observe that now there was a fork that was joined at the merge commit. 65 | 66 | Conflict resolution: 67 | 68 | 1. Repeat the exercises above, but change the README file both locally and remotely. Resolve the conflict using both merge and rebase. 69 | 70 | 71 | -------------------------------------------------------------------------------- /tutorials/removing_sensitive_files.md: -------------------------------------------------------------------------------- 1 | # Fixing mistakes 2: Removing sensitive files 2 | 3 | We all know the problem: you accidentally commit a file you really shouldn't have added to github. 4 | Of course, you can `git rm` the file to remove and it will be removed from the active version of the repository. 5 | More generally, you can use `git revert HEAD~1` to undo the last commit (`HEAD~1`), which automatically creates a new commit that undos the previous commit. 6 | 7 | However, removing the file through normal means does not suffice for a file containing e.g. a password or private key or private or copyrighted data you are not allowed to share, as the file(s) can still be found in the commit history. 8 | 9 | So, how to completely erase a file from a git(hub) repository? 10 | 11 | # Scenario 1: You added and/or committed the file, but did not push yet 12 | 13 | This is the easy case, and you can use the normal troubleshooting approaches here: 14 | 15 | + If you added but did not commit, use `git restore --staged secret.txt` 16 | + If you committed, but did not push, undo the add and commit using `git reset HEAD~` (where `HEAD~` means 1 commit before HEAD). 17 | Alternatively, if you want to keep the rest of the commit, but only remove the offending file from the commit, use `git rm --cached secret.txt` (you can omit the `--cached` if you want to delete the file from disk as well, and then *amend* your last commit with `git commit --amend`. 18 | 19 | # Scenario 2: You just pushed the commit containing the sensitive file 20 | 21 | This is still easy from a technical perspective, as you can remove your last commit locally (`git reset HEAD~`) or edit it (with `git rm` followed by `git commit --amend`). However, this means that your last commit does not have the remote HEAD as parent, so you need to **force push** it with `git push --force`. This sets the remote HEAD to your last commit (either the amended one or the one before the offending one), and makes the commit containing the secret file an orphan commit which can no longer be found. 22 | 23 | Note that git also has a *reference log* to recent commits, in case you accidentally mess something up and lose track of a commit. 24 | To also clear that log, use `git reflog expire --expire=now --all` and `git gc --prune=now --aggressive`. 25 | 26 | # Aside: On rewriting history 27 | 28 | The big difference between reverting a commit (which creates an 'undo commit') and actually removing a commit with a force push is that rather than having the history reflect the addition and removal, it has now *rewritten history* with no trace left of the removed file. 29 | Now, this is 'dangerous', in the sense that if another user pulled or cloned the repository in the meantime, they still have the secret file locally, and moreover their HEAD now points to a commit that is no longer in the remote repository, so they will get all kind of trouble if they continue working with it. 30 | 31 | This means that for rewriting history: 32 | 33 | + *Only rewrite history in emergency*, i.e. in case of accidentally publishing something secret, private, or confidential -- not for fixing a regular mistake or making the commit history look prettier. 34 | + *Always notify you co-authors* about your force push so they can make sure their code is still on the main line, and not on the abandoned line containing the offending commit. 35 | 36 | Finally, you should realize that even if the file can no longer be found on github normally, it can still be in someones local repository or a cache. 37 | So, if it's a password or certificate, assume that it is exposed and change the password/certificate. 38 | Also, if it is super sensitive, contact github to ask them to remove all traces from their cache. See [this github page](https://docs.github.com/en/github/authenticating-to-github/removing-sensitive-data-from-a-repository) for more information. 39 | 40 | # Scenario 3: The sensitive file has been in the repository for a while 41 | 42 | This is in a way the biggest challenge, as you would have to change all commits in history that reference the sensitive file(s). 43 | Fortunately, this is relatively easy with the [bfg](https://rtyley.github.io/bfg-repo-cleaner/) tool. 44 | 45 | First, download the tool and make sure you have java installed. If you call the tool like this, it should display information on how to use the tool: 46 | 47 | ```{sh} 48 | $ java -jar ~/Downloads/bfg-1.13.2.jar 49 | bfg 1.13.2 50 | Usage: bfg [options] [] 51 | [..] 52 | ``` 53 | 54 | Now that you know that the tool is correctly installed, the following steps will help you remove a file: 55 | 56 | 1. Notify any collaborators about your mistake, that you're about to change history, and tell them to commit any outstanding changes they have and remove local versions of the repository 57 | 2. Create a backup of the repository by cloning it somewhere safe 58 | 3. Make sure any local changes are committed, and remove your local clone and make a fresh clone (`rm -rf REPONAME; git clone git@github.com/USER/REPONAME`) 59 | 4. Run the bfg tool like this to change the existing commits: (make sure to check the output for errors. If you mess up, go back to step 3) 60 | 61 | ```{sh} 62 | $ java -jar ~/Downloads/bfg-1.13.2.jar sensitivefilename.txt 63 | ``` 64 | 65 | 5. Remove references to the old commits: `git reflog expire --expire=now --all && git gc --prune=now --aggressive` 66 | 6. Force push to github: `git push -f` 67 | 7. Check that on github all references to the file(s) are gone 68 | 8. Tell your collaborators to re-clone the repository. 69 | 70 | Note: It's important to inform your collaborators of this, since if they keep the local repository they will be on a commit that no longer exists, so they will not be able to commit or pull changes. If they then decide to force push, it would bring the sensitive file back to github. In general, whenever you need to change history on github like this, it's important to make sure that there are no collaborators working with the 'old' version of the repository. 71 | -------------------------------------------------------------------------------- /tutorials/resolving_conflicts.md: -------------------------------------------------------------------------------- 1 | # Resolving conflicts 2 | 3 | In the previous step you learned about pushing and pulling. 4 | You also learned that you should push and pull often to stay nicely in sync with the 5 | remote repository. 6 | However, even if you do this diligently, you will at some point get into a 'conflict' 7 | if you're working with others on the same repository. 8 | 9 | The problem is simple: say you want to *push* some changes to the remote repository. 10 | But suddenly git refuses, because someone else already pushed some changed the remote repository since you last *pulled*. 11 | Rule of the streets is that it's now your responsibility to fix this. 12 | 13 | One of the best things about Git is that it actually helps you resolve these conflicts. 14 | However, before we talk about how this works, and what techniques you can use for properly resolving conflicts, we're going to focus on the most common types of conflicts, and the most simple solutions. 15 | 16 | 17 | # A simple conflict 18 | 19 | The common case of conflict we'll focus on, is that you committed some changes 20 | to your local repository and want to push them, but while you were working on 21 | these changes, someone else beat you to the push. In storyboard: 22 | 23 | * You: `pull` 24 | * Someone else: `push` 25 | * You: `push` 26 | * GitHub: **no >:(** 27 | 28 | Git will now tell you: `failed to push some refs to [respository]`, and tips that 29 | `Updates were rejected because the remote contains work that you do not have locally.` 30 | 31 | Sound's fun, so let's orchestrate it. Remember that in the previous tutorial we manually 32 | committed a change on GitHub? This time we're doing the same thing, but instead of pulling, 33 | we're going to try and push our own local changes. Specifically, take the following steps. 34 | 35 | * 1. Go to your GitHub repository 36 | * 2. Open the README.md file, and add some text to it 37 | * 3. Commit the changes 38 | 39 | This changed the `remote repository`. Now let's change the `local repository`, 40 | and try to push it. We're going to create a new file called `conflict.txt` containing 41 | just the text "foreboding". 42 | 43 | ``` 44 | $ echo "foreboding" > conflict.txt 45 | ``` 46 | 47 | Now add, commit and push. 48 | 49 | ``` 50 | $ git add conflict.txt 51 | $ git commit -m "boy, I sure hope nobody pushed before me" 52 | $ git push 53 | ``` 54 | 55 | If we did good (bad?) you should now receive the error mentioned above. 56 | (You might receive a similar but different message, depending on system/version). 57 | 58 | ## A simple solution 59 | 60 | In the error message git already gives the hint to use `git pull`. 61 | If we do this, Git will automatically try to merge the repositories. 62 | This is good, but we're going to use a little variation called *rebasing*. 63 | This solves the same problem, but in a different way. 64 | We'll talk more about the difference between merge and rebase in one of the more 65 | advanced tutorials. 66 | For now, just assume that rebasing is often a good approach. 67 | It works as follows. 68 | 69 | ``` 70 | $ git pull --rebase 71 | ``` 72 | 73 | What happened, is that git now first pulled the updated remote repository, and then 74 | just committed your change **on top of it**. 75 | 76 | And that actually solved the problem. Check `git status` to be sure. 77 | This should now tell you that you're 1 commit ahead. So let's push: 78 | 79 | ``` 80 | $ git push 81 | ``` 82 | 83 | And now you can check the GitHub repository to see that it all worked out. 84 | 85 | 86 | # A slightly less simple problem 87 | 88 | The previous problem was easy to solve, because the changes that you made in the `local repository` were in a different file from the changes that you made to the `remote repository`. 89 | But another very real scenario is that you and a collaborator both made changes 90 | to the same file, and perhaps even the same lines of code. 91 | In this case, Git can't just merge the changes or perform the rebase. 92 | 93 | To orchestrate this, we'll first make some changes to the remote repo: 94 | 95 | * 1. Go to your GitHub repository 96 | * 2. Open the conflict.txt file, and change the text to "Marco" 97 | * 3. Commit the changes 98 | 99 | Now we'll also change the conflict.txt file locally, and then add, commit and (try to) push. 100 | 101 | ``` 102 | $ echo "Polo" > conflict.txt 103 | $ git add conflict.txt 104 | $ git commit -m "surely nobody touched this file" 105 | $ git push 106 | ``` 107 | 108 | Now you get the same error as before. 109 | What you don't yet know, is that the problem is actually much worse. 110 | This you'll only learn after trying to rebase 111 | 112 | ``` 113 | $ git pull --rebase 114 | ``` 115 | 116 | The message you get is pretty long and scary. It talks about a merge conflict, and 117 | failing to deal with it. 118 | 119 | ## A decently simple solution 120 | 121 | If you look at the last few lines of the error message, you see that there's hope. 122 | However, we will need to get our manual hands dirty. 123 | Luckily, Git has marked the conflicts that it encountered, so you just need to 124 | ask Git where it found them, and then manually fix the problems. 125 | When you fixed the, you can run `git rebase --continue`. 126 | 127 | Actually, let's just run this right now: 128 | 129 | ``` 130 | $ git rebase --continue 131 | ``` 132 | 133 | This should tell you that conflict.txt needs merge, and that you must edit all 134 | merge conflicts and mark them as resolved (with git add). You can open 135 | conflict.txt and look for the conflict. Git clearly marks them with `<<<<<<< HEAD` 136 | You can also follow the hint to run `git am --show-current-patch` to see where the 137 | conflict is, but in practise it's often easier to just open the problematic files 138 | and search for `<<<<<<`. 139 | 140 | Now open conflict.txt in your plain text editor. You'll see something weird: 141 | 142 | ``` 143 | <<<<<<< HEAD 144 | polo 145 | ======= 146 | marco 147 | >>>>>>> surely nobody touched this file 148 | ``` 149 | 150 | So what do we see: 151 | 152 | * the start of the conflict is marked with `<<<<<<< HEAD`, and the end is marked with `>>>>>> [your commit message]`. Note that in this case we didn't have any text before 153 | * the change that was added on the `remote repository` is shown above the `=======` line 154 | * the change you made in the `local repository` is shown below the `=======` line 155 | 156 | Basically, you now just fix it in your text editor. You, as the intelligent human, decide how to resolve the conflict: is either marco or polo the better commit, or maybe some combination? Then just remove the whole chunk from start to end, and replace it with your solution. For this example, just replace it with "marco polo!!" 157 | 158 | Now we mark them as resolved with add, and continue the rebase. 159 | 160 | ``` 161 | $ git add conflict.txt 162 | $ git rebase --continue 163 | ``` 164 | 165 | And now the conflict should be solved, and we can push. 166 | 167 | ``` 168 | $ git push 169 | ``` 170 | 171 | Check on GitHub to verify if it worked. The conflict.txt file should now say "marco polo!!" 172 | 173 | 174 | ## A super simple but super inelegant solution 175 | 176 | There is another... solution. Remember that [xkcd comic](https://xkcd.com/1597/) we began the workshop with? 177 | It actually refers to these types of situations. 178 | And the solution proposed in this comic, though far from elegant, can be a lifesaver 179 | if you just really need to push something but forgot the whole --rebase dance. 180 | 181 | That solution is: 182 | 183 | * Make a back up of your repository 184 | * Delete the repository, and make a fresh clone 185 | * Now just redo/copy whatever changes you made in the fresh clone 186 | 187 | Off course, this isn't really a good option if you made many changes. Maybe the conflict is 188 | just one line somewhere, in which case the rebase dance is a much better solution. But if you're really 189 | stuck, this can be a last resort hack. 190 | 191 | 192 | 193 | --------------------------------------------------------------------------------