forked from jennybc/happy-git-with-r
-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
2 changed files
with
87 additions
and
68 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,20 @@ | ||
# Branches {#git-branches} | ||
|
||
Branching means that you take a detour from the main stream of development and | ||
do work without changing the main stream. It allows one or many people to work | ||
in parallel without overwriting each other's work. | ||
do work without changing the main stream. | ||
It allows one or many people to work in parallel without overwriting each other's work. | ||
It allows a someone working solo to work incrementally on an experimental idea, without jeopardizing the state of the main product. | ||
|
||
Branching in git is very lightweight, which means creating a branch and | ||
switching between branches is nearly instantaneous. This means git encourages | ||
workflows which create small branches for exploration or new features, often | ||
merging them back together quickly. | ||
Branching in Git is very lightweight, which means creating a branch and | ||
switching between branches is nearly instantaneous. | ||
This means Git encourages workflows which create small branches for exploration or new features, often merging them back together quickly. | ||
|
||
## Create a new branch | ||
|
||
You can create a new branch with `git branch`, then checkout the branch with `git checkout`. To distinguish it from the main stream of development, presumably on `master`, we'll call this a "feature branch". | ||
You can create a new branch with `git branch`, then checkout the branch with `git checkout`. | ||
To distinguish it from the main stream of development, presumably on `main`, we'll call this a "feature branch". | ||
|
||
```shell | ||
```console | ||
git branch issue-5 | ||
git checkout issue-5 | ||
``` | ||
|
@@ -27,57 +28,61 @@ Once you have switched to a branch, you can commit to it as usual. | |
You use `git checkout` to switch between branches. | ||
|
||
But what do you do if you are working on a branch and need to switch, | ||
but the work on the current branch is not complete? One option is the [Git | ||
stash](https://git-scm.com/book/en/v2/ch00/_git_stashing), but generally a | ||
better option is to safeguard the current state with a temporary commit. Here I | ||
use "WIP" as the commit message to indicate work in progress. | ||
but the work on the current branch is not complete? | ||
One option is the [Git stash](https://git-scm.com/book/en/v2/ch00/_git_stashing), but generally a better option is to safeguard the current state with a temporary commit. | ||
Here I use "WIP" as the commit message to indicate work in progress. | ||
|
||
```shell | ||
```console | ||
git commit --all -m "WIP" | ||
git checkout master | ||
git checkout main | ||
``` | ||
|
||
Then when you come back to the branch and continue your work, you | ||
need to undo the temporary commit by [resetting](#reset) your state. Specifically, we want a mixed reset. This is "working directory safe", i.e. it does not affect the state of any files. But it does peel off the temporary WIP commit. Below, the reference `HEAD^` says to roll the commit state back to the parent of the current commit (`HEAD`). | ||
need to undo the temporary commit by [resetting](#reset) your state. | ||
Specifically, we want a mixed reset. | ||
This is "working directory safe", i.e. it does not affect the state of any files. | ||
But it does peel off the temporary WIP commit. | ||
Below, the reference `HEAD^` says to roll the commit state back to the parent of the current commit (`HEAD`). | ||
|
||
```shell | ||
```console | ||
git checkout issue-5 | ||
git reset HEAD^ | ||
``` | ||
|
||
If this is difficult to remember, or to roll the commit state back to a different previous state, the reference can also be given as the SHA of a specific commit, which you can see via `git log`. | ||
This is where I think a graphical Git client can be invaluable, as you can generally right click on the target commit, then select the desired type of reset (e.g., soft, mixed, or hard). | ||
This is exactly the type of intermediate-to-advanced Git usage that often feels more approachable in a graphical client. | ||
|
||
## Merging a branch | ||
|
||
Once you have done your work and committed it to the feature branch, you can switch back to `master` and merge the feature branch. | ||
Once you have done your work and committed it to the feature branch, you can switch back to `main` and merge the feature branch. | ||
|
||
```shell | ||
git checkout master | ||
```console | ||
git checkout main | ||
git merge issue-5 | ||
``` | ||
|
||
## Dealing with conflicts | ||
|
||
Most of the time, the merge will go smoothly. However if both the branches you | ||
are merging changed the same part of the same file you will get a merge | ||
conflict. | ||
Most of the time, the merge will go smoothly. | ||
However if both the branches you are merging changed the same part of the same file you will get a merge conflict. | ||
|
||
```shell | ||
```console | ||
git merge issue-5 | ||
# Auto-merging index.html | ||
# CONFLICT (content): Merge conflict in index.html | ||
# Automatic merge failed; fix conflicts and then commit the result. | ||
``` | ||
|
||
The first thing to do is **NOT PANIC**. Merge conflicts are not the end of the | ||
world and most are relatively small and straightforward to resolve. | ||
The first thing to do is **NOT PANIC**. | ||
Merge conflicts are not the end of the world and most are relatively small and straightforward to resolve. | ||
|
||
The first step to solving a merge conflict is determining which files are in | ||
conflict, which you can do with `git status`: | ||
|
||
```shell | ||
git status | ||
# On branch master | ||
# On branch main | ||
# You have unmerged paths. | ||
# (fix conflicts and run "git commit") | ||
# | ||
|
@@ -89,8 +94,8 @@ git status | |
# no changes added to commit (use "git add" and/or "git commit -a") | ||
``` | ||
|
||
So this shows only `index.html` is unmerged and needs to be resolved. We can | ||
then open the file to see what lines are in conflict. | ||
So this shows only `index.html` is unmerged and needs to be resolved. | ||
We can then open the file to see what lines are in conflict. | ||
|
||
```html | ||
<<<<<<< HEAD:index.html | ||
|
@@ -103,24 +108,28 @@ then open the file to see what lines are in conflict. | |
``` | ||
|
||
In this conflict, the lines between `<<<<<< HEAD:index.html` and `======` are | ||
the content from the branch you are currently on. The lines between `=======` | ||
and `>>>>>>> issue-5:index.html` are from the feature branch we are merging. | ||
the content from the branch you are currently on. | ||
The lines between `=======` and `>>>>>>> issue-5:index.html` are from the feature branch we are merging. | ||
|
||
To resolve the conflict, edit this section until it reflects the state you want in the merged result. Pick one version or the other or create a hybrid. Also remove the conflict markers `<<<<<<`, `======` and `>>>>>>`. | ||
To resolve the conflict, edit this section until it reflects the state you want in the merged result. | ||
Pick one version or the other or create a hybrid. | ||
Also remove the conflict markers `<<<<<<`, `======` and `>>>>>>`. | ||
|
||
```html | ||
<div id="footer"> | ||
please contact us at [email protected] | ||
</div> | ||
``` | ||
|
||
Now run `git add index.html` and `git commit` to finalize the merge. CONFLICTS RESOLVED. | ||
Now run `git add index.html` and `git commit` to finalize the merge. | ||
CONFLICTS RESOLVED. | ||
|
||
### Bailing out | ||
|
||
If, during the merge, you get confused about the state of things or make a | ||
mistake, use `git merge --abort` to abort the merge and go back to the state | ||
prior to running `git merge`. Then you can try to complete the merge again. | ||
prior to running `git merge`. | ||
Then you can try to complete the merge again. | ||
|
||
Git Basic Branching and Merging: | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,8 +1,9 @@ | ||
# Remotes {#git-remotes} | ||
|
||
Remote repositories are versions of your project that are hosted on the | ||
Internet or another network. A single project can have 1, 2 or even hundreds of | ||
remotes. You pull others changes from remotes and push your changes to remotes. | ||
Internet or another network. | ||
A single project can have 1, 2, or even hundreds of remotes. | ||
You pull others' changes from remotes and push your changes to remotes. | ||
|
||
```{r setup, include = FALSE} | ||
has_bash <- Sys.which('bash') != '' && .Platform$OS.type != 'windows' | ||
|
@@ -20,40 +21,48 @@ git remote -v | |
## Adding a new remote | ||
|
||
`git clone` automatically adds a new remote, so often you do not need to do | ||
this manually initially. However, after the initial clone, it is often useful to | ||
add additional remotes. | ||
this manually initially. | ||
However, after the initial clone, it is often useful to add additional remotes. | ||
|
||
Use `git remote add` to add a new remote | ||
Use `git remote add` to add a new remote: | ||
|
||
```shell | ||
```console | ||
git remote add happygit https://github.com/jennybc/happy-git-with-r.git | ||
``` | ||
|
||
Note: when you add a remote you give it a nickname (here `happygit`), which you can use in git commands in place of the entire URL. | ||
|
||
```shell | ||
```console | ||
git fetch happygit | ||
``` | ||
|
||
Sidebar on nicknames: there is a strong convention to use `origin` as the nickname of your main remote. At this point, it is common for the main remote of a repo to be hosted on GitHub (or GitLab or Bitbucket). It is tempting to use a more descriptive nickname (such as `github`), but you might find that following convention is worth it. It makes your setup easier for others to understand and for you to transfer information that you read in documentation, on Stack Overflow, or in blogs. | ||
Sidebar on nicknames: there is a strong convention to use `origin` as the nickname of your main remote. | ||
At this point, it is common for the main remote of a repo to be hosted on GitHub (or GitLab or Bitbucket). | ||
It is tempting to use a more descriptive nickname (such as `github`), but you might find that following convention is worth it. | ||
It makes your setup easier for others to understand and for you to transfer information that you read in documentation, on Stack Overflow, or in blogs. | ||
|
||
A common reason to add a second remote is when you have done a "fork and clone" of a repo and your personal copy is set up as the `origin` remote. Eventually you will want to pull changes from the original repository. It is common to use `upstream` as the nickname for this remote. | ||
A common reason to add a second remote is when you have done a "fork and clone" of a repo and your personal copy (your fork) is set up as the `origin` remote. | ||
Eventually you will want to pull changes from the original repository. It is common to use `upstream` as the nickname for this remote. | ||
|
||
```console | ||
git remote add upstream https://github.com/TRUE_OWNER/REPO.git | ||
``` | ||
|
||
## Fetching data from remotes | ||
|
||
To get new data from a remote use `git fetch <remote_name>`. This retrieves the | ||
data locally, but importantly it does _not_ change the state of your repository | ||
or your files in any way. To incorporate the data into your repository, you need to merge or rebase your project with the remote project. | ||
To get new data from a remote use `git fetch <remote_name>`. | ||
This retrieves the data locally, but importantly it does _not_ change the state of your local files in any way. | ||
To incorporate the data into your repository, you need to merge or rebase your project with the remote project. | ||
|
||
```shell | ||
```console | ||
# Fetch the data | ||
git fetch happygit | ||
|
||
# Now merge it with our local master | ||
git merge happygit/master master | ||
# Now merge it with our local main | ||
git merge happygit/main main | ||
|
||
# git pull is a shortcut which does the above in one command | ||
git pull happygit master | ||
git pull happygit main | ||
``` | ||
|
||
For more detail on `git pull` workflows, see \@ref(pull-tricky). | ||
|
@@ -63,47 +72,49 @@ For more detail on `git pull` workflows, see \@ref(pull-tricky). | |
Use `git push <remote> <branch>` to push your local changes to the `<branch>` | ||
branch on the `<remote>` remote. | ||
|
||
```shell | ||
# push my local changes to the origin remote's master branch | ||
git push origin master | ||
```console | ||
# push my local changes to the origin remote's main branch | ||
git push origin main | ||
|
||
# push my local changes to the happygit remote's test branch | ||
git push happygit test | ||
``` | ||
|
||
## Renaming and changing remotes | ||
|
||
`git remote rename` can be used to rename a remote | ||
`git remote rename` can be used to rename a remote: | ||
|
||
```shell | ||
```console | ||
git remote rename happygit hg | ||
``` | ||
|
||
`git remote set-url` can be used to change the URL for a remote. This is | ||
sometimes useful if you initially set up a remote using https, but now want to | ||
use the SSH URL instead (or vise versa). | ||
`git remote set-url` can be used to change the URL for a remote. | ||
This is sometimes useful if you initially set up a remote using HTTPS, but now want to use SSH instead (or *vice versa*). | ||
|
||
```shell | ||
```console | ||
git remote set-url happygit [email protected]:jennybc/happy-git-with-r.git | ||
``` | ||
|
||
One fairly common workflow is you initially cloned a repository on GitHub | ||
locally (without forking it), but now want to create your own fork and push | ||
changes to it. As described earlier, it is common to call the main repository `upstream` and to call your fork `origin`. So, in this case, you need to first rename the existing remote (from `origin` to `upstream`). Then add your fork as a new remote, with the name `origin`. | ||
changes to it. | ||
As described earlier, it is common to call the source repository `upstream` and to call your fork `origin`. | ||
So, in this case, you need to first rename the existing remote (from `origin` to `upstream`). | ||
Then add your fork as a new remote, with the name `origin`. | ||
|
||
```shell | ||
```console | ||
git remote rename origin upstream | ||
git remote add origin [email protected]:jimhester/happy-git-with-r.git | ||
``` | ||
|
||
## Upstream tracking branches | ||
|
||
It is possible to set the branch on the remote each of your local remotes | ||
corresponds to. `git clone` sets this up automatically, so for your own master | ||
branch this is not something you will run into. However by default if you | ||
create a new branch and try to push to it you will see something like this. | ||
corresponds to. | ||
`git clone` sets this up automatically, so for your own `main` branch this is not something you will run into. | ||
However by default if you create a new branch and try to push to it you will see something like this: | ||
|
||
```shell | ||
```console | ||
git checkout -b mybranch | ||
git push | ||
# fatal: The current branch foo has no upstream branch. | ||
|
@@ -113,13 +124,12 @@ git push | |
``` | ||
|
||
You can do as the error message says and explicitly set the upstream branch | ||
with `--set-upstream`. However I would recommend instead changing the default | ||
behavior of `push` to automatically set the upstream branch to the branch with | ||
the same name on the remote. | ||
with `--set-upstream`. | ||
However I would recommend instead changing the default behavior of `push` to automatically set the upstream branch to the branch with the same name on the remote. | ||
|
||
You can do this by changing the git `push.default` option to `current`. | ||
|
||
```shell | ||
```console | ||
git config --global push.default current | ||
``` | ||
|
||
|