summaryrefslogtreecommitdiff
path: root/doc/topics/git
diff options
context:
space:
mode:
Diffstat (limited to 'doc/topics/git')
-rw-r--r--doc/topics/git/git_rebase.md272
-rw-r--r--doc/topics/git/img/git_rebase_v13_5.pngbin0 -> 49048 bytes
-rw-r--r--doc/topics/git/index.md1
3 files changed, 273 insertions, 0 deletions
diff --git a/doc/topics/git/git_rebase.md b/doc/topics/git/git_rebase.md
new file mode 100644
index 00000000000..6f50dea26dd
--- /dev/null
+++ b/doc/topics/git/git_rebase.md
@@ -0,0 +1,272 @@
+---
+stage: Create
+group: Source Code
+info: "To determine the technical writer assigned to the Stage/Group associated with this page, see https://about.gitlab.com/handbook/engineering/ux/technical-writing/#designated-technical-writers"
+type: concepts, howto
+description: "Introduction to Git rebase, force-push, and resolving merge conflicts through the command line."
+---
+
+# Introduction to Git rebase, force-push, and merge conflicts
+
+This guide helps you to get started with rebasing, force-pushing, and fixing
+merge conflicts locally.
+
+Before diving into this document, make sure you are familiar with using
+[Git through the command line](../../gitlab-basics/start-using-git.md).
+
+## Git rebase
+
+[Rebasing](https://git-scm.com/docs/git-rebase) is a very common operation in
+Git. There are the following rebase options:
+
+- [Regular rebase](#regular-rebase).
+- [Interactive rebase](#interactive-rebase).
+
+### Before rebasing
+
+CAUTION: **Warning:**
+`git rebase` rewrites the commit history. It **can be harmful** to do it in
+shared branches. It can cause complex and hard to resolve merge conflicts. In
+these cases, instead of rebasing your branch against the default branch,
+consider pulling it instead (`git pull origin master`). It has a similar
+effect without compromising the work of your contributors.
+
+It's safer to back up your branch before rebasing to make sure you don't lose
+any changes. For example, consider a [feature branch](../../gitlab-basics/start-using-git.md#branching)
+called `my-feature-branch`:
+
+1. Open your feature branch in the terminal:
+
+ ```shell
+ git checkout my-feature-branch
+ ```
+
+1. Checkout a new branch from it:
+
+ ```shell
+ git checkout -b my-feature-branch-backup
+ ```
+
+1. Go back to your original branch:
+
+ ```shell
+ git checkout my-feature-branch
+ ```
+
+Now you can safely rebase it. If anything goes wrong, you can recover your
+changes by resetting `my-feature-branch` against `my-feature-branch-backup`:
+
+1. Make sure you're in the correct branch (`my-feature-branch`):
+
+ ```shell
+ git checkout my-feature-branch
+ ```
+
+1. Reset it against `my-feature-branch-backup`:
+
+ ```shell
+ git reset --hard my-feature-branch-backup
+ ```
+
+Note that if you added changes to `my-feature-branch` after creating the backup branch,
+you will lose them when resetting.
+
+### Regular rebase
+
+With a regular rebase you can update your feature branch with the default
+branch (or any other branch).
+This is an important step for Git-based development strategies. You can
+ensure that the changes you're adding to the codebase do not break any
+existing changes added to the target branch _after_ you created your feature
+branch.
+
+For example, to update your branch `my-feature-branch` with `master`:
+
+1. Fetch the latest changes from `master`:
+
+ ```shell
+ git fetch origin master
+ ```
+
+1. Checkout your feature branch:
+
+ ```shell
+ git checkout my-feature-branch
+ ```
+
+1. Rebase it against `master`:
+
+ ```shell
+ git rebase origin/master
+ ```
+
+1. [Force-push](#force-push) to your branch.
+
+When you rebase:
+
+1. Git imports all the commits submitted to `master` _after_ the
+ moment you created your feature branch until the present moment.
+1. Git puts the commits you have in your feature branch on top of all
+ the commits imported from `master`:
+
+![Git rebase illustration](img/git_rebase_v13_5.png)
+
+You can replace `master` with any other branch you want to rebase against, for
+example, `release-10-3`. You can also replace `origin` with other remote
+repositories, for example, `upstream`. To check what remotes you have linked to your local
+repository, you can run `git remote -v`.
+
+If there are [merge conflicts](#merge-conflicts), Git will prompt you to fix
+them before continuing the rebase.
+
+To learn more, check Git's documentation on [rebasing](ttps://git-scm.com/book/en/v2/Git-Branching-Rebasing)
+and [rebasing strategies](https://git-scm.com/book/en/v2/Git-Branching-Rebasing).
+
+### Interactive rebase
+
+You can use interactive rebase to modify commits. For example, amend a commit
+message, squash (join multiple commits into one), edit, or delete
+commits. It is handy for changing past commit messages,
+as well as for organizing the commit history of your branch to keep it clean.
+
+TIP: **Tip:**
+If you want to keep the default branch commit history clean, you don't need to
+manually squash all your commits before merging every merge request;
+with [Squash and Merge](../../user/project/merge_requests/squash_and_merge.md)
+GitLab does it automatically.
+
+When you want to change anything in recent commits, use interactive
+rebase by passing the flag `--interactive` (or `-i`) to the rebase command.
+
+For example, if you want to edit the last three commits in your branch
+(`HEAD~3`), run:
+
+```shell
+git rebase -i HEAD~3
+```
+
+Git opens the last three commits in your terminal text editor and describes
+all the interactive rebase options you can use. The default option is `pick`,
+which maintains the commit unchanged. Replace the keyword `pick` according to
+the operation you want to perform in each commit. To do so, you need to edit
+the commits in your terminal's text editor.
+
+For example, if you're using [Vim](https://www.vim.org/) as the text editor in
+a macOS's `ZSH` shell, and you want to **squash** all the three commits
+(join them into one):
+
+1. Press <kbd>i</kbd> on your keyboard to switch to Vim's editing mode.
+1. Navigate with your keyboard arrows to edit the **second** commit keyword
+ from `pick` to `squash` (or `s`). Do the same to the **third** commit.
+ The first commit should be left **unchanged** (`pick`) as we want to squash
+ the second and third into the first.
+1. Press <kbd>Esc</kbd> to leave the editing mode.
+1. Type `:wq` to "write" (save) and "quit".
+1. Git outputs the commit message so you have a chance to edit it:
+ - All lines starting with `#` will be ignored and not included in the commit
+ message. Everything else will be included.
+ - To leave it as it is, type `:wq`. To edit the commit message: switch to the
+ editing mode, edit the commit message, and save it as you just did.
+1. If you haven't pushed your commits to the remote branch before rebasing,
+ push your changes normally. If you had pushed these commits already,
+ [force-push](#force-push) instead.
+
+Note that the steps for editing through the command line can be slightly
+different depending on your operating system and the shell you're using.
+
+See [Numerous undo possibilities in Git](numerous_undo_possibilities_in_git/index.md#with-history-modification)
+for a deeper look into interactive rebase.
+
+## Force-push
+
+When you perform more complex operations, for example, squash commits, reset or
+rebase your branch, you'll have to _force_ an update to the remote branch,
+since these operations imply rewriting the commit history of the branch.
+To force an update, pass the flag `--force` or `-f` to the `push` command. For
+example:
+
+```shell
+git push --force origin my-feature-branch
+```
+
+Forcing an update is **not** recommended when you're working on shared
+branches.
+
+Alternatively, you can pass the flag [`--force-with-lease`](https://git-scm.com/docs/git-push#Documentation/git-push.txt---force-with-leaseltrefnamegt)
+instead. It is safer, as it does not overwrite any work on the remote
+branch if more commits were added to the remote branch by someone else:
+
+```shell
+git push --force-with-lease origin my-feature-branch
+```
+
+If the branch you want to force-push is [protected](../../user/project/protected_branches.md),
+you can't force-push to it unless you unprotect it first. Then you can
+force-push and re-protect it.
+
+## Merge conflicts
+
+As Git is based on comparing versions of a file
+line-by-line, whenever a line changed in your branch coincides with the same
+line changed in the target branch (after the moment you created your feature branch from it), Git
+identifies these changes as a merge conflict. To fix it, you need to choose
+which version of that line you want to keep.
+
+Most conflicts can be [resolved through the GitLab UI](../../user/project/merge_requests/resolve_conflicts.md).
+
+For more complex cases, there are various methods for resolving them. There are
+also [Git GUI apps](https://git-scm.com/downloads/guis) that can help by
+visualizing the differences.
+
+To fix conflicts locally, you can use the following method:
+
+1. Open the terminal and checkout your feature branch, for example, `my-feature-branch`:
+
+ ```shell
+ git checkout my-feature-branch
+ ```
+
+1. [Rebase](#regular-rebase) your branch against the target branch so Git
+ prompts you with the conflicts:
+
+ ```shell
+ git rebase origin/master
+ ```
+
+1. Open the conflicting file in a code editor of your preference.
+1. Look for the conflict block:
+ - It begins with the marker: `<<<<<<< HEAD`.
+ - Below, there is the content with your changes.
+ - The marker: `=======` indicates the end of your changes.
+ - Below, there's the content of the latest changes in the target branch.
+ - The marker `>>>>>>>` indicates the end of the conflict.
+1. Edit the file: choose which version (before or after `=======`) you want to
+ keep, and then delete the portion of the content you don't want in the file.
+1. Delete the markers.
+1. Save the file.
+1. Repeat the process if there are other conflicting files.
+1. Stage your changes:
+
+ ```shell
+ git add .
+ ```
+
+1. Commit your changes:
+
+ ```shell
+ git commit -m "Fix merge conflicts"
+ ```
+
+1. Continue rebasing:
+
+ ```shell
+ git rebase --continue
+ ```
+
+ CAUTION: **Caution:**
+ Up to this point, you can run `git rebase --abort` to stop the process.
+ Git aborts the rebase and rolls back the branch to the state you had before
+ running `git rebase`.
+ Once you run `git rebase --continue` the rebase **cannot** be aborted.
+
+1. [Force-push](#force-push) to your remote branch.
diff --git a/doc/topics/git/img/git_rebase_v13_5.png b/doc/topics/git/img/git_rebase_v13_5.png
new file mode 100644
index 00000000000..ff29fa97798
--- /dev/null
+++ b/doc/topics/git/img/git_rebase_v13_5.png
Binary files differ
diff --git a/doc/topics/git/index.md b/doc/topics/git/index.md
index 92181fb7bb0..cb2d7b74522 100644
--- a/doc/topics/git/index.md
+++ b/doc/topics/git/index.md
@@ -81,6 +81,7 @@ If you have problems with Git, the following may help:
The following are advanced topics for those who want to get the most out of Git:
+- [Introduction to Git rebase, force-push, and merge conflicts](git_rebase.md)
- [Server Hooks](../../administration/server_hooks.md)
- [Git Attributes](../../user/project/git_attributes.md)
- Git Submodules: [Using Git submodules with GitLab CI](../../ci/git_submodules.md#using-git-submodules-with-gitlab-ci)