snapshot of https://github.com/zulip/zulip.git @ 48c69911c7dd4e03b20552eb3bd77ad8151c1357 (2026-09-15)
Some checks failed
Code scanning / CodeQL (push) Failing after 15s
Zulip production suite / Ubuntu 22.04 production build (push) Failing after 26s
Zulip production suite / Debian 12 production install with custom db name and user (push) Has been skipped
Zulip production suite / Ubuntu 22.04 production install and PostgreSQL upgrade with pgroonga (push) Has been skipped
Zulip production suite / Ubuntu 24.04 production install (push) Has been skipped
Zulip production suite / Ubuntu 26.04 production install (push) Has been skipped
Zulip production suite / Debian 13 production install (push) Has been skipped
Zulip production suite / 7.0 Version Upgrade (push) Has been skipped
Zulip production suite / 8.0 Version Upgrade (push) Has been skipped
Zulip production suite / 6.0 Version Upgrade (push) Has been skipped
Zulip production suite / 10.0 Version Upgrade (push) Has been skipped
Zulip production suite / 9.0 Version Upgrade (push) Has been skipped
Zulip production suite / 12.0 Version Upgrade (push) Has been skipped
Zulip production suite / 11.0 Version Upgrade (push) Has been skipped
GitHub Actions Security Analysis with zizmor / zizmor (push) Failing after 3s
Zulip CI / Debian 12 (Python 3.11, backend + documentation) (push) Failing after 26s
Zulip CI / Ubuntu 22.04 (Python 3.10, backend + frontend) (push) Failing after 3s
Zulip CI / Ubuntu 24.04 (Python 3.12, backend) (push) Failing after 25s
Zulip CI / Ubuntu 26.04 (Python 3.14, backend) (push) Failing after 25s
Zulip CI / Debian 13 (Python 3.13, backend) (push) Failing after 28s
Zulip production suite / Required jobs (push) Has been cancelled
Zulip CI / Required jobs (push) Has been cancelled
API Documentation Update Check / check-feature-level-updated (push) Has been cancelled
API Documentation Update Check / notify-if-api-docs-changed (push) Has been cancelled

This commit is contained in:
upstream-mirror
2026-09-15 15:05:30 +05:00
commit 64898b2c79
8999 changed files with 1757358 additions and 0 deletions

118
docs/git/cheat-sheet.md Normal file
View File

@@ -0,0 +1,118 @@
# Git cheat sheet
See also [fixing commits][fix-commit]
## Common commands
- add
- `git add foo.py`
- checkout
- `git checkout -b new-branch-name`
- `git checkout main`
- `git checkout old-branch-name`
- commit
- `git commit -m "topic: Commit message title."`
- `git commit --amend`: Modify the previous commit.
- config
- `git config --global core.editor nano`
- `git config --global core.symlinks true`
- diff
- `git diff`
- `git diff --cached`
- `git diff HEAD~2..`
- fetch
- `git fetch origin`
- `git fetch upstream`
- grep
- `git grep update_unread_counts`
- log
- `git log`
- pull
- `git pull --rebase`: **Use this**. Zulip uses a [rebase oriented workflow][git-overview].
- `git pull` (with no options): Will either create a merge commit
(which you don't want) or do the same thing as `git pull --rebase`,
depending on [whether you've configured Git properly][git-config-clone]
- push
- `git push origin +branch-name`
- rebase
- `git rebase -i HEAD~3`
- `git rebase -i main`
- `git rebase upstream/main`
- reflog
- `git reflog | head -10`
- remote
- `git remote -v`
- reset
- `git reset HEAD~2`
- rm
- `git rm oops.txt`
- show
- `git show HEAD`
- `git show HEAD~~~`
- `git show main`
- status
- `git status`
## Detailed cheat sheet
- add
- `git add foo.py`: add `foo.py` to the staging area
- `git add foo.py bar.py`: add `foo.py` AND `bar.py` to the staging area
- `git add -u`: Adds all tracked files to the staging area.
- checkout
- `git checkout -b new-branch-name`: create branch `new-branch-name` and switch to/check out that new branch
- `git checkout main`: switch to your `main` branch
- `git checkout old-branch-name`: switch to an existing branch `old-branch-name`
- commit
- `git commit -m "commit message"`: It is recommended to type a
multiline commit message, however.
- `git commit`: Opens your default text editor to write a commit message.
- `git commit --amend`: changing the last commit message. Read more [here][fix-commit]
- config
- `git config --global core.editor nano`: set core editor to `nano` (you can set this to `vim` or others)
- `git config --global core.symlinks true`: allow symbolic links
- diff
- `git diff`: display the changes you have made to all files
- `git diff --cached`: display the changes you have made to staged files
- `git diff HEAD~2..`: display the 2 most recent changes you have made to files
- fetch
- `git fetch origin`: fetch origin repository
- `git fetch upstream`: fetch upstream repository
- grep
- `git grep update_unread_counts web/src`: Search our JS for references to update_unread_counts.
- log
- `git log`: show commit logs
- `git log --oneline | head`: To quickly see the latest ten commits on a branch.
- `git log -p`: show commit logs with changes; see [the "secret" to reading it's output][git-log-secret]
- pull
- `git pull --rebase`: rebase your changes on top of `main`.
- `git pull` (with no options): Will either create a merge commit
(which you don't want) or do the same thing as `git pull --rebase`,
depending on [whether you've configured Git properly][git-config-clone]
- push
- `git push origin branch-name`: push you commits to the origin repository _only if_ there are no conflicts.
Use this when collaborating with others to prevent overwriting their work.
- `git push origin +branch-name`: force push your commits to your origin repository.
- rebase
- `git rebase -i HEAD~3`: interactive rebasing current branch with first three items on HEAD
- `git rebase -i main`: interactive rebasing current branch with `main` branch
- `git rebase upstream/main`: rebasing current branch with `main` branch from upstream repository
- reflog
- `git reflog | head -10`: manage reference logs for the past 10 commits
- remote
- `git remote -v`: display your origin and upstream repositories
- reset
- `git reset HEAD~2`: reset two most recent commits
- rm
- `git rm oops.txt`: remove `oops.txt`
- show
- `git show HEAD`: display most recent commit
- `git show HEAD~~~`: display third most recent commit
- `git show main`: display most recent commit on `main`
- status
- `git status`: show the working tree status, unstaged and staged files
[fix-commit]: fixing-commits.md
[git-log-secret]: reading-history.md#the-secret-to-using-git-log--p
[git-config-clone]: cloning.md#step-1b-clone-to-your-machine
[git-overview]: overview.md

140
docs/git/cloning.md Normal file
View File

@@ -0,0 +1,140 @@
# Get Zulip code
Zulip uses a **forked-repo** and **[rebase][gitbook-rebase]-oriented
workflow**. This means that all contributors create a fork of the [Zulip
repository][github-zulip] they want to contribute to and then submit pull
requests to the upstream repository to have their contributions reviewed and
accepted. We also recommend you work on feature branches.
## Step 1a: Create your fork
The following steps you'll only need to do the first time you set up a machine
for contributing to a given Zulip project. You'll need to repeat the steps for
any additional Zulip projects ([list][github-zulip]) that you work on.
The first thing you'll want to do to contribute to Zulip is fork ([see
how][github-help-fork]) the appropriate [Zulip repository][github-zulip]. For
the main server app, this is [zulip/zulip][github-zulip-zulip].
## Step 1b: Clone to your machine
Next, clone your fork to your local machine:
```console
$ git clone --config pull.rebase https://github.com/YOUR_USERNAME/zulip.git
Cloning into 'zulip'
remote: Counting objects: 86768, done.
remote: Compressing objects: 100% (15/15), done.
remote: Total 86768 (delta 5), reused 1 (delta 1), pack-reused 86752
Receiving objects: 100% (86768/86768), 112.96 MiB | 523.00 KiB/s, done.
Resolving deltas: 100% (61106/61106), done.
Checking connectivity... done.
```
(The `--config pull.rebase` option configures Git so that `git pull`
will behave like `git pull --rebase` by default. Using
`git pull --rebase` to update your changes to resolve merge conflicts
is expected by essentially all of open source projects, including
Zulip. You can also set that option after cloning using
`git config --add pull.rebase true`, or just be careful to always run
`git pull --rebase`, never `git pull`).
Note: If you receive an error while cloning, you may not have [added your ssh
key to GitHub][github-help-add-ssh-key].
Once the repository is cloned, we recommend running
[setup-git-repo][zulip-rtd-tools-setup] to install Zulip's pre-commit
hook which runs the Zulip linters on the changed files when you
commit.
## Step 1c: Connect your fork to Zulip upstream
Next you'll want to [configure an upstream remote
repository][github-help-conf-remote] for your fork of Zulip. This will allow
you to [sync changes][github-help-sync-fork] from the main project back into
your fork.
First, show the currently configured remote repository:
```console
$ git remote -v
origin git@github.com:YOUR_USERNAME/zulip.git (fetch)
origin git@github.com:YOUR_USERNAME/zulip.git (push)
```
Note: If you've cloned the repository using a graphical client, you may already
have the upstream remote repository configured. For example, when you clone
[zulip/zulip][github-zulip-zulip] with the GitHub desktop client it configures
the remote repository `zulip` and you see the following output from
`git remote -v`:
```console
origin git@github.com:YOUR_USERNAME/zulip.git (fetch)
origin git@github.com:YOUR_USERNAME/zulip.git (push)
zulip https://github.com/zulip/zulip.git (fetch)
zulip https://github.com/zulip/zulip.git (push)
```
If your client hasn't automatically configured a remote for zulip/zulip, you'll
need to with:
```console
$ git remote add -f upstream https://github.com/zulip/zulip.git
```
Finally, confirm that the new remote repository, upstream, has been configured:
```console
$ git remote -v
origin git@github.com:YOUR_USERNAME/zulip.git (fetch)
origin git@github.com:YOUR_USERNAME/zulip.git (push)
upstream https://github.com/zulip/zulip.git (fetch)
upstream https://github.com/zulip/zulip.git (push)
```
## Step 2: Set up the Zulip development environment
If you haven't already, now is a good time to install the Zulip development environment
([overview][zulip-rtd-dev-overview]). If you're new to working on Zulip or open
source projects in general, we recommend following our [detailed guide for
first-time contributors][zulip-rtd-dev-first-time].
## Step 3: Configure continuous integration for your fork
This step is optional, but recommended.
The Zulip Server project is configured to use [GitHub Actions][github-actions]
to test and create builds upon each new commit and pull request.
GitHub Actions is the primary CI that runs frontend and backend
tests across a wide range of Ubuntu distributions.
GitHub Actions is free for open source projects and it's easy to
configure for your own fork of Zulip. After doing so, GitHub Actions
will run tests for new refs you push to GitHub and email you the outcome
(you can also view the results in the web interface).
Running CI against your fork can help save both your and the
Zulip maintainers time by making it easy to test a change fully before
submitting a pull request. We generally recommend a workflow where as
you make changes, you use a fast edit-refresh cycle running individual
tests locally until your changes work. But then once you've gotten
the tests you'd expect to be relevant to your changes working, push a
branch to run the full test suite in GitHub Actions before
you create a pull request. While you wait for GitHub Actions jobs
to run, you can start working on your next task. When the tests finish,
you can create a pull request that you already know passes the tests.
GitHub Actions will run all the jobs by default on your forked repository.
You can check the `Actions` tab of your repository to see the builds.
[gitbook-rebase]: https://git-scm.com/book/en/v2/Git-Branching-Rebasing
[github-help-add-ssh-key]: https://help.github.com/en/articles/adding-a-new-ssh-key-to-your-github-account
[github-help-conf-remote]: https://help.github.com/en/articles/configuring-a-remote-for-a-fork
[github-help-fork]: https://help.github.com/en/articles/fork-a-repo
[github-help-sync-fork]: https://help.github.com/en/articles/syncing-a-fork
[github-zulip]: https://github.com/zulip/
[github-zulip-zulip]: https://github.com/zulip/zulip/
[github-actions]: https://docs.github.com/en/actions
[zulip-rtd-dev-first-time]: ../development/setup-recommended.md
[zulip-rtd-dev-overview]: ../development/overview.md
[zulip-rtd-tools-setup]: zulip-tools.md#set-up-git-repo-script

59
docs/git/collaborate.md Normal file
View File

@@ -0,0 +1,59 @@
# Collaborate
## Fetch another contributor's branch
What happens when you would like to collaborate with another contributor and
they have work-in-progress on their own fork of Zulip? No problem! Just add
their fork as a remote and pull their changes.
```console
$ git remote add <username> https://github.com/<username>/zulip.git
$ git fetch <username>
```
Now you can check out their branch just like you would any other. You can name
the branch anything you want, but using both the username and branch name will
help you keep things organized.
```console
$ git checkout -b <username>/<branchname>
```
You can choose to rename the branch if you prefer:
```bash
git checkout -b <custombranchname> <username>/<branchname>
```
## Check out a pull request locally
Just as you can check out any user's branch locally, you can also check out any
pull request locally. GitHub provides a special syntax
([details][github-help-co-pr-locally]) for this since pull requests are
specific to GitHub rather than Git.
First, fetch and create a branch for the pull request, replacing _ID_ and
_BRANCHNAME_ with the ID of the pull request and your desired branch name:
```console
$ git fetch upstream pull/ID/head:BRANCHNAME
```
Now switch to the branch:
```console
$ git checkout BRANCHNAME
```
Now you work on this branch as you would any other.
Note: you can use the scripts provided in the tools/ directory to fetch pull
requests. You can read more about what they do [here][tools-pr].
```bash
tools/fetch-rebase-pull-request <PR-number>
tools/fetch-pull-request <PR-number>
```
[github-help-co-pr-locally]: https://help.github.com/en/articles/checking-out-pull-requests-locally
[tools-pr]: zulip-tools.md#fetch-a-pull-request-and-rebase

View File

@@ -0,0 +1,45 @@
# Fixing commits
This is mostly from
[here](https://help.github.com/en/articles/changing-a-commit-message#rewriting-the-most-recent-commit-message).
## Fixing the last commit
### Changing the last commit message
1. `git commit --amend -m "New message"`
### Changing the last commit
1. Make your changes to the files
2. Run `git add <filename>` to add one file or `git add <filename1> <filename2> ...` to add multiple files
3. `git commit --amend`
## Fixing older commits
### Changing commit messages
1. `git rebase -i HEAD~5` (if, for example, you are editing some of the last five commits)
2. For each commit that you want to change the message, change `pick` to `reword`, and save
3. Change the commit messages
### Deleting old commits
1. `git rebase -i HEAD~n` where `n` is the number of commits you are looking at
2. For each commit that you want to delete, change `pick` to `drop`, and save
## Squashing commits
Sometimes, you want to make one commit out of a bunch of commits. To do this,
1. `git rebase -i HEAD~n` where `n` is the number of commits you are interested in
2. Change `pick` to `squash` on the lines containing the commits you want to squash and save
## Reordering commits
1. `git rebase -i HEAD~n` where `n` is the number of commits you are interested in
2. Reorder the lines containing the commits and save
## Pushing commits after tidying them
1. `git push origin +my-feature-branch` (Note the `+` there and substitute your actual branch name.)

23
docs/git/index.md Normal file
View File

@@ -0,0 +1,23 @@
# Git guide
```{toctree}
---
maxdepth: 3
---
Quick start <overview>
Set up Git <setup>
Zulip-specific tools <zulip-tools>
How Git is different <the-git-difference>
Important Git terms <terminology>
Get Zulip code <cloning>
Working copies <working-copies>
Using Git as you work <using>
Pull requests <pull-requests>
Collaborate <collaborate>
Fixing commits <fixing-commits>
Reviewing changes <reviewing>
Reading history <reading-history>
Get and stay out of trouble <troubleshooting>
Git cheat sheet <cheat-sheet>
```

73
docs/git/overview.md Normal file
View File

@@ -0,0 +1,73 @@
# Quick start: how Zulip uses Git and GitHub
This quick start provides a brief overview of how Zulip uses Git and GitHub.
Those who are familiar with Git and GitHub should be able to start contributing
with these details in mind:
- We use **GitHub for source control and code review.** To contribute, fork
[zulip/zulip][github-zulip-zulip] (or the appropriate
[repository][github-zulip], if you are working on something else besides
Zulip server) to your own account and then create feature/issue branches.
When you're ready to get feedback, submit a [draft][github-help-draft-pr]
pull request. _We encourage you to submit draft pull requests early and
often._
- We use a **[rebase][gitbook-rebase]-oriented workflow.** We do not use merge
commits. This means you should use `git fetch` followed by `git rebase`
rather than `git pull` (or you can use `git pull --rebase`). Also, to prevent
pull requests from becoming out of date with the main line of development,
you should rebase your feature branch prior to submitting a pull request, and
as needed thereafter. If you're unfamiliar with how to rebase a pull request,
[read this excellent guide][edx-howto-rebase-pr].
We use this strategy in order to avoid the extra commits that appear
when another branch is merged, that clutter the commit history (it's
popular with other large projects such as Django). This makes
Zulip's commit history more readable, but a side effect is that many
pull requests we merge will be reported by GitHub's UI as _closed_
instead of _merged_, since GitHub has poor support for
rebase-oriented workflows.
- We have a **[code style guide][zulip-rtd-code-style]**, a **[commit message
guide][zulip-rtd-commit-messages]**, and strive for each commit to be _a
minimal coherent idea_ (see **[commit
discipline][zulip-rtd-commit-discipline]** for details).
- We provide **many tools to help you submit quality code.** These include
[linters][zulip-rtd-lint-tools], [tests][zulip-rtd-testing], [continuous
integration][continuous-integration] and [mypy][zulip-rtd-mypy].
- We use [zulipbot][zulip-rtd-zulipbot-usage] to manage our issues and
pull requests to create a better GitHub workflow for contributors.
- We provide some handy **[Zulip-specific Git scripts][zulip-rtd-zulip-tools]**
for developers to easily do tasks like fetching and rebasing a pull
request, cleaning unimportant branches, etc. These reduce the common
tasks of testing other contributors' pull requests to single commands.
Finally, install the [Zulip developer environment][zulip-rtd-dev-overview], and then
[configure continuous integration for your fork][zulip-git-guide-fork-ci].
---
The following sections will help you be awesome with Zulip and Git/GitHub in a
rebased-based workflow. Read through it if you're new to Git, to a rebase-based
Git workflow, or if you'd like a Git refresher.
[github-help-draft-pr]: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests#draft-pull-requests
[gitbook-rebase]: https://git-scm.com/book/en/v2/Git-Branching-Rebasing
[edx-howto-rebase-pr]: https://web.archive.org/web/20240204225038/https://github.com/openedx/edx-platform/wiki/How-to-Rebase-a-Pull-Request
[github-zulip]: https://github.com/zulip/
[github-zulip-zulip]: https://github.com/zulip/zulip/
[continuous-integration]: ../testing/continuous-integration.md
[zulip-git-guide-fork-ci]: cloning.md#step-3-configure-continuous-integration-for-your-fork
[zulip-rtd-code-style]: ../contributing/code-style.md
[zulip-rtd-commit-discipline]: ../contributing/commit-discipline.md
[zulip-rtd-commit-messages]: ../contributing/commit-discipline.md
[zulip-rtd-dev-overview]: ../development/overview.md
[zulip-rtd-lint-tools]: ../contributing/code-style.md#use-the-linters
[zulip-rtd-mypy]: ../testing/mypy.md
[zulip-rtd-testing]: ../testing/testing.md
[zulip-rtd-zulip-tools]: zulip-tools.md
[zulip-rtd-zulipbot-usage]: ../contributing/zulipbot-usage.md

163
docs/git/pull-requests.md Normal file
View File

@@ -0,0 +1,163 @@
# Pull requests
When you're ready for feedback, submit a pull request. Pull requests
are a feature specific to GitHub. They provide a simple, web-based way
to submit your work (often called "patches") to a project. It's called
a _pull request_ because you're asking the project to _pull changes_
from your fork.
If you're unfamiliar with how to create a pull request, you can check
out GitHub's documentation on
[creating a pull request from a fork][github-help-create-pr-fork]. You
might also find GitHub's article
[about pull requests][github-help-about-pr] helpful. That all said,
the tutorial below will walk you through the process.
## Draft pull requests
In the Zulip project, we encourage submitting [draft pull
requests][github-help-draft-pr] early and often. This allows you to
share your code to make it easier to get feedback and help with your
changes, even if you don't think your pull request is ready to be
merged (e.g., it might not work or pass tests). This sets expectations
correctly for any feedback from other developers, and prevents your
work from being merged before you're confident in it.
## Create a pull request
### Step 0: Make sure you're on a feature branch (not `main`)
It is important to [work on a feature
branch](using.md#work-on-a-feature-branch) when creating a pull
request. Your new pull request will be inextricably linked with your
branch while it is open, so you will need to reserve your branch only
for changes related to your issue, and avoid introducing extraneous
changes for other issues or from upstream.
If you are working on a branch named `main`, you need to create and
switch to a feature branch before proceeding.
### Step 1: Update your branch with git rebase
The best way to update your branch is with `git fetch` and `git rebase`. Do not
use `git pull` or `git merge` as this will create merge commits. See [keep your
fork up to date][keep-up-to-date] for details.
Here's an example (you would replace _issue-123_ with the name of your feature branch):
```console
$ git checkout issue-123
Switched to branch 'issue-123'
$ git fetch upstream
remote: Counting objects: 69, done.
remote: Compressing objects: 100% (23/23), done.
remote: Total 69 (delta 49), reused 39 (delta 39), pack-reused 7
Unpacking objects: 100% (69/69), done.
From https://github.com/zulip/zulip
69fa600..43e21f6 main -> upstream/main
$ git rebase upstream/main
First, rewinding head to replay your work on top of it...
Applying: troubleshooting tip about provisioning
```
### Step 2: Push your updated branch to your remote fork
Once you've updated your local feature branch, push the changes to GitHub:
```console
$ git push origin issue-123
Counting objects: 6, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (6/6), 658 bytes | 0 bytes/s, done.
Total 6 (delta 3), reused 0 (delta 0)
remote: Resolving deltas: 100% (3/3), completed with 1 local objects.
To git@github.com:christi3k/zulip.git
+ 2d49e2d...bfb2433 issue-123 -> issue-123
```
If your push is rejected with error **failed to push some refs** then you need
to prefix the name of your branch with a `+`:
```console
$ git push origin +issue-123
Counting objects: 6, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (6/6), 658 bytes | 0 bytes/s, done.
Total 6 (delta 3), reused 0 (delta 0)
remote: Resolving deltas: 100% (3/3), completed with 1 local objects.
To git@github.com:christi3k/zulip.git
+ 2d49e2d...bfb2433 issue-123 -> issue-123 (forced update)
```
This is perfectly okay to do on your own feature branches, especially if you're
the only one making changes to the branch. If others are working along with
you, they might run into complications when they retrieve your changes because
anyone who has based their changes off a branch you rebase will have to do a
complicated rebase.
### Step 3: Open the pull request
If you've never created a pull request or need a refresher, take a look at
GitHub's article on [creating a pull request from a
fork][github-help-create-pr-fork]. We'll briefly review the process here.
First, sign in to GitHub on your web browser and navigate to your fork of Zulip.
Next, navigate to the branch you've been working on. Do this by clicking on the
**Branch** button and selecting the relevant branch. Finally, click the **New
pull request** button. Alternatively, if you've recently pushed the relevant
branch to your fork, you will see a **Compare & pull request** button.
A pull request template will open with some information pre-filled in.
Provide (or update) the title for your pull request and write a first comment.
If your pull request makes UI changes, always include one or more still
screenshots to demonstrate your changes. If it seems helpful, add a brief
video of the new functionality as well. Take time to read our
[comprehensive guide to capturing screenshots](../contributing/presenting-visual-changes.md),
which includes [a list of screenshot tools][screenshots-gifs] you can use.
See the documentation for creating [reviewable pull requests][reviewable-prs]
for more guidance and tips when writing pull request comments. If the repository
has a self-review checklist in the pull request template, make sure that all the
relevant points have been addressed before submitting it.
When ready, click the **Create pull request** button to submit the pull request.
Remember to mark your pull request as a [draft][github-help-draft-pr] if it is a
work-in-progress.
Note: **Pull request titles are different from commit messages.** Commit
messages can be edited with `git commit --amend`, `git rebase -i`, etc., while
the title of a pull request can only be edited via GitHub.
## Update a pull request
As you get make progress on your feature or bugfix, your pull request, once
submitted, will be updated each time you [push commits][self-push-commits] to
your remote branch. This means you can keep your pull request open as long as
you need, rather than closing and opening new ones for the same feature or
bugfix.
It's a good idea to keep your pull request mergeable with Zulip upstream by
frequently fetching, rebasing, and pushing changes. See [keep your fork up to
date][keep-up-to-date] for details. You might also find this excellent
article [How to Rebase a Pull Request][edx-howto-rebase-pr] helpful.
And, as you address review comments others have made, we recommend posting a
follow-up comment in which you: a) ask for any clarifications you need, b)
explain to the reviewer how you solved any problems they mentioned, and c) ask
for another review.
[edx-howto-rebase-pr]: https://web.archive.org/web/20240204225038/https://github.com/openedx/edx-platform/wiki/How-to-Rebase-a-Pull-Request
[github-help-about-pr]: https://help.github.com/en/articles/about-pull-requests
[github-help-create-pr-fork]: https://help.github.com/en/articles/creating-a-pull-request-from-a-fork
[github-help-draft-pr]: https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/about-pull-requests#draft-pull-requests
[keep-up-to-date]: using.md#keep-your-fork-up-to-date
[self-push-commits]: using.md#push-your-commits-to-github
[screenshots-gifs]: ../contributing/presenting-visual-changes.md#screenshot-and-gif-software
[reviewable-prs]: ../contributing/reviewable-prs.md

View File

@@ -0,0 +1,88 @@
# Reading history
One of the things that makes Git so valuable is its facilities for
studying history -- both
- very recent history (e.g., rereading your own branch before you
send a PR), and
- the distant past (e.g., tracking down when and why some piece
of code became the way it is.)
This guide, written by Greg Price, will help you take advantage of
these powerful abilities.
## Use a graphical client
One great way to read history: [use a graphical Git client](setup.md#get-a-graphical-client)!
Especially helpful for
- reading through the recent commits, or
- clarifying how branches are related to each other.
## The "secret" to using `git log -p`
Use `git log -p`, with this important secret:
- In the pager that `git log` puts you into, hit `/` to search, then enter
the pattern `^c` -- that is, caret, then `c`. Then hit `n`/`N` for
next/previous match.
- This finds lines that begin with `c`. Because of thoughtful design in
the default format of `git log`, these are exactly the first line of the
log entry for each commit. So with this search pattern, you effectively
get **keybindings for "next/previous commit"**. This makes a huge
difference in skimming quickly past boring commits without missing
anything.
- For a further upgrade, use `git log --stat -p` (you might alias this as
e.g., `git lsp`.) Now every time you hit `n` or `N`, you see the commit
message and complete list of affected files for the new commit -- a good
summary to help decide whether to read in more detail or hit `n`/`N`
again to move on.
## Filter `git log` down to relevant commits
Use some of `git log`'s many features to filter down to commits you
care about. For example:
- Filter to a range of commits with `git log A..B`. E.g., to reread your
current branch relative to upstream main, you might say
`git log --stat -p upstream/main..`, or `git log --stat -p @{u}..`.
(Greg has the latter aliased as `git usp`, and types it constantly.)
- Filter to changes touching certain files or directories:
`git log PATHS`.
- Filter to changes touching lines that mention some pattern:
`git log -G PATTERN`.
- Filter to changes adding or removing mentions of some pattern:
`git log -S PATTERN`. This feature is traditionally called the
"pickaxe", presumably in honor of its power to mine just the right bit
of historical/explanatory gold.
- Many more. Do take a few minutes to skim through the documentation in
`git help log` (or [this web version](https://git-scm.com/docs/git-log))
to get an idea of what's available; and perhaps an hour now and then to
read and try things in more detail.
## Filter in your graphical client
Try all those `git log` filtering features in your graphical client -- it
may even support the very same command-line options to do it. For
example, `gitk upstream/main..` shows basically the same information as
`git log --stat -p upstream/main..`, but graphically.
## Git a summary, with `git log --oneline`
Try `git log --graph --oneline --decorate --boundary`. (Quite a mouthful;
Greg has this aliased as `git k`, in homage to `gitk`.) It can be a
lightweight alternative to your graphical client for simple, routine
situations, giving a compact list of commits each on just one line.
- To list the commits local to your current branch: `git k @{u}..`.
(Greg has an alias for this, and types it constantly.)
- To list all your own local commits on all branches:
`git k --branches @ --not --remotes=origin --remotes=upstream`.
(For explanation, see `git help log`.)

64
docs/git/reviewing.md Normal file
View File

@@ -0,0 +1,64 @@
# Review changes
**Note** - The following section covers reviewing changes on your local
clone. Please read the section on [code reviews][zulip-rtd-review] for a guide
on reviewing changes by other contributors.
## Changes on (local) working tree
Display changes between index and working tree (what is not yet staged for commit):
```console
$ git diff
```
Display changes between index and last commit (what you have staged for commit):
```console
$ git diff --cached
```
Display changes in working tree since last commit (changes that are staged as
well as ones that are not):
```console
$ git diff HEAD
```
## Changes within branches
Use any git-ref to compare changes between two commits on the current branch.
Display changes between commit before last and last commit:
```console
$ git diff HEAD^ HEAD
```
Display changes between two commits using their hashes:
```console
$ git diff e2f404c 7977169
```
## Changes between branches
Display changes between tip of `topic` branch and tip of `main` branch:
```console
$ git diff topic main
```
Display changes that have occurred on `main` branch since `topic` branch was created:
```console
$ git diff topic...main
```
Display changes you've committed so far since creating a branch from `upstream/main`:
```console
$ git diff upstream/main...HEAD
```
[zulip-rtd-review]: ../contributing/code-reviewing.md

72
docs/git/setup.md Normal file
View File

@@ -0,0 +1,72 @@
# Set up Git
If you're already using Git, have a client you like, and a GitHub account, you
can skip this section. Otherwise, read on!
## Install and configure Git, join GitHub
If you're not already using Git, you might need to [install][gitbook-install]
and [configure][gitbook-setup] it.
**If you are using Windows 10 without [WSL
2](https://docs.microsoft.com/en-us/windows/wsl/wsl2-about), make sure you
[are running Git BASH as an administrator][git-bash-admin] at all times.**
You'll also need a GitHub account, which you can sign up for
[here][github-join].
We highly recommend you create an SSH key if you don't already have
one and [add it to your GitHub account][github-help-add-ssh-key]. If
you don't, you'll have to type your GitHub username and password every
time you interact with GitHub, which is usually several times a day.
We also highly recommend the following:
- [Configure Git][gitbook-config] with your name and email and
[aliases][gitbook-aliases] for commands you'll use often. We
recommend using your full name (not just your first name), since
that's what we'll use to give credit to your work in places like the
Zulip release notes.
- Install the command auto-completion and/or git-prompt plugins available for
[Bash][gitbook-other-envs-bash] and [Zsh][gitbook-other-envs-zsh].
If you are installing the Zulip development environment, now you are ready to
continue with [Step 1: Install prerequisites](../development/setup-recommended.md#step-1-install-prerequisites).
## Get a graphical client
Even if you're comfortable using Git on the command line, having a graphical
client can be useful for viewing your repository. This is especially true
when doing complicated rebases and similar operations because you can check
the state of your repository after each command to see what changed. If
something goes wrong, this helps you figure out when and why.
If you don't already have one installed, here are some suggestions:
- macOS: [GitX][gitgui-gitx] (previously [GitX-dev][gitgui-gitxdev])
- Ubuntu/Linux: [git-cola][gitgui-gitcola], [gitg][gitgui-gitg], [gitk][gitgui-gitk]
- Windows: [SourceTree][gitgui-sourcetree]
If you like working on the command line, but want better visualization and
navigation of your Git repo, try [Tig][tig], a cross-platform ncurses-based
text-mode interface to Git.
And, if none of the above are to your liking, try [one of these][gitbook-guis].
[git-bash-admin]: ../development/setup-advanced.md#running-git-bash-as-an-administrator
[gitbook-aliases]: https://git-scm.com/book/en/v2/Git-Basics-Git-Aliases
[gitbook-config]: https://git-scm.com/book/en/v2/Customizing-Git-Git-Configuration
[gitbook-guis]: https://git-scm.com/downloads/guis
[gitbook-install]: https://git-scm.com/book/en/v2/Getting-Started-Installing-Git
[github-join]: https://github.com/join
[gitbook-setup]: https://git-scm.com/book/en/v2/Getting-Started-First-Time-Git-Setup
[gitbook-other-envs-bash]: https://git-scm.com/book/en/v2/Appendix-A%3A-Git-in-Other-Environments-Git-in-Bash
[gitbook-other-envs-zsh]: https://git-scm.com/book/en/v2/Appendix-A%3A-Git-in-Other-Environments-Git-in-Zsh
[gitgui-gitcola]: https://git-cola.github.io/
[gitgui-gitg]: https://wiki.gnome.org/Apps/Gitg
[gitgui-gitk]: https://git-scm.com/docs/gitk
[gitgui-gitx]: https://github.com/gitx/gitx/
[gitgui-gitxdev]: https://rowanj.github.io/gitx/
[gitgui-sourcetree]: https://www.sourcetreeapp.com/
[github-help-add-ssh-key]: https://help.github.com/en/articles/adding-a-new-ssh-key-to-your-github-account
[tig]: https://jonas.github.io/tig/

96
docs/git/terminology.md Normal file
View File

@@ -0,0 +1,96 @@
# Important Git terms
When you install Git, it adds a manual entry for `gitglossary`. You can view
this glossary by running `man gitglossary`. Below we've included the Git terms
you'll encounter most often along with their definitions from _gitglossary_.
## branch
A "branch" is an active line of development. The most recent commit
on a branch is referred to as the tip of that branch. The tip of
the branch is referenced by a branch head, which moves forward as
additional development is done on the branch. A single Git
repository can track an arbitrary number of branches, but your
working tree is associated with just one of them (the "current" or
"checked out" branch), and HEAD points to that branch.
## cache
Obsolete for: index
## checkout
The action of updating all or part of the working tree with a tree
object or blob from the object database, and updating the index and
HEAD if the whole working tree has been pointed at a new branch.
## commit
As a noun: A single point in the Git history; the entire history of
a project is represented as a set of interrelated commits. The word
"commit" is often used by Git in the same places other revision
control systems use the words "revision" or "version". Also used as
a short hand for commit object.
As a verb: The action of storing a new snapshot of the project's
state in the Git history, by creating a new commit representing the
current state of the index and advancing HEAD to point at the new
## fast-forward
A fast-forward is a special type of merge where you have a revision
and you are "merging" another branch's changes that happen to be a
descendant of what you have. In such these cases, you do not make a
new merge commit but instead just update to their revision. This will
happen frequently on a remote-tracking branch of a remote
repository.
## fetch
Fetching a branch means to get the branch's head ref from a remote
repository, to find out which objects are missing from the local
object database, and to get them, too. See also [git-fetch(1)](https://git-scm.com/docs/git-fetch)
## hash
In Git's context, synonym for object name.
## head
A named reference to the commit at the tip of a branch. Heads are
stored in a file in $GIT_DIR/refs/heads/ directory, except when
using packed refs. See also [git-pack-refs(1)](https://git-scm.com/docs/git-pack-refs).
## HEAD
The current branch. In more detail: Your working tree is normally
derived from the state of the tree referred to by HEAD. HEAD is a
reference to one of the heads in your repository, except when using
a detached HEAD, in which case it directly references an arbitrary
commit.
## index
A collection of files with stat information, whose contents are
stored as objects. The index is a stored version of your working
tree. Truth be told, it can also contain a second, and even a third
version of a working tree, which are used when merging.
## pull
Pulling a branch means to fetch it and merge it. See also [git-pull(1)](https://git-scm.com/docs/git-pull)
## push
Pushing a branch means to get the branch's head ref from a remote
repository, find out if it is a direct ancestor to the branch's
local head ref, and in that case, putting all objects, which are
reachable from the local head ref, and which are missing from the
remote repository, into the remote object database, and updating
the remote head ref. If the remote head is not an ancestor to the
local head, the push fails.
## rebase
To reapply a series of changes from a branch to a different base,
and reset the head of that branch to the result.

View File

@@ -0,0 +1,64 @@
# How Git is different
Whether you're new to Git or have experience with another version control
system (VCS), it's a good idea to learn a bit about how Git works. We recommend
this excellent presentation _[Understanding Git][understanding-git]_ from
Nelson Elhage and Anders Kaseorg and the [Git Basics][gitbook-basics] chapter
from _Pro Git_ by Scott Chacon and Ben Straub.
Here are the top things to know:
- **Git works on snapshots.** Unlike other version control systems (e.g.,
Subversion, Perforce, Bazaar), which track files and changes to those files
made over time, Git tracks _snapshots_ of your project. Each time you commit
or otherwise make a change to your repository, Git takes a snapshot of your
project and stores a reference to that snapshot. If a file hasn't changed,
Git creates a link to the identical file rather than storing it again.
- **Most Git operations are local.** Git is a distributed version control
system, so once you've cloned a repository, you have a complete copy of that
repository's _entire history_. Staging, committing, branching, and browsing
history are all things you can do locally without network access and without
immediately affecting any remote repositories. To make or receive changes
from remote repositories, you need to `git fetch`, `git pull`, or `git push`.
- **Nearly all Git actions add information to the Git database**, rather than
removing it. As such, it's hard to make Git perform actions that you can't
undo. However, Git can't undo what it doesn't know about, so it's a good
practice to frequently commit your changes and frequently push your commits to
your remote repository.
- **Git is designed for lightweight branching and merging.** Branches are
simply references to snapshots. It's okay and expected to make a lot of
branches, even throwaway and experimental ones.
- **Git stores all data as objects, of which there are four types:** blob
(file), tree (directory), commit (revision), and tag. Each of these objects
is named by a unique hash, the SHA-1 hash of its contents. Most of the time
you'll refer to objects by their truncated hash or more human-readable
reference like `HEAD` (the current branch). Blobs and trees represent files
and directories. Tags are named references to other objects. A commit object
includes: tree id, zero or more parents as commit ids, an author (name,
email, date), a committer (name, email, date), and a log message. A Git
repository is a collection of mutable pointers to these objects called
**refs**.
- **Cloning a repository creates a working copy.** Every working copy has a
`.git` subdirectory, which contains its own Git repository. The `.git`
subdirectory also tracks the _index_, a staging area for changes that will
become part of the next commit. All files outside of `.git` are the _working
tree_.
- **Files tracked with Git have three possible states: committed, modified, and
staged.** Committed files are those safely stored in your local `.git`
repository/database. Staged files have changes and have been marked for
inclusion in the next commit; they are part of the index. Modified files have
changes but have not yet been marked for inclusion in the next commit; they
have not been added to the index.
- **Git commit workflow is as follows.** Edit files in your _working tree_. Add
to the _index_ (that is _stage_) with `git add`. _Commit_ to the HEAD of the
current branch with `git commit`.
[gitbook-basics]: https://git-scm.com/book/en/v2/Git-Basics-Getting-a-Git-Repository
[understanding-git]: https://web.mit.edu/nelhage/Public/git-slides-2009.pdf

284
docs/git/troubleshooting.md Normal file
View File

@@ -0,0 +1,284 @@
# Get and stay out of trouble
Git is a powerful yet complex version control system. Even for contributors
experienced at using version control, it can be confusing. The good news is
that nearly all Git actions add information to the Git database, rather than
removing it. As such, it's hard to make Git perform actions that you can't
undo. However, Git can't undo what it doesn't know about, so it's a good
practice to frequently commit your changes and frequently push your commits to
your remote repository.
## Undo a merge commit
A merge commit is a special type of commit that has two parent commits. It's
created by Git when you merge one branch into another and the last commit on
your current branch is not a direct ancestor of the branch you are trying to
merge in. This happens quite often in a busy project like Zulip where there are
many contributors because upstream/zulip will have new commits while you're
working on a feature or bugfix. In order for Git to merge your changes and the
changes that have occurred on zulip/upstream since you first started your work,
it must perform a three-way merge and create a merge commit.
Merge commits aren't bad, however, Zulip doesn't use them. Instead Zulip uses a
forked-repo, rebase-oriented workflow.
A merge commit is usually created when you've run `git pull` or `git merge`.
You'll know you're creating a merge commit if you're prompted for a commit
message and the default is something like this:
```text
Merge branch 'main' of https://github.com/zulip/zulip
# Please enter a commit message to explain why this merge is necessary,
# especially if it merges an updated upstream into a topic branch.
#
# Lines starting with '#' will be ignored, and an empty message aborts
# the commit.
```
And the first entry for `git log` will show something like:
```console
commit e5f8211a565a5a5448b93e98ed56415255546f94
Merge: 13bea0e e0c10ed
Author: Christie Koehler <ck@christi3k.net>
Date: Mon Oct 10 13:25:51 2016 -0700
Merge branch 'main' of https://github.com/zulip/zulip
```
Some graphical Git clients may also create merge commits.
To undo a merge commit, first run `git reflog` to identify the commit you want
to roll back to:
```console
$ git reflog
e5f8211 HEAD@{0}: pull upstream main: Merge made by the 'recursive' strategy.
13bea0e HEAD@{1}: commit: test commit for docs.
```
Reflog output will be long. The most recent Git refs will be listed at the top.
In the example above `e5f8211 HEAD@{0}:` is the merge commit made automatically
by `git pull` and `13bea0e HEAD@{1}:` is the last commit I made before running
`git pull`, the commit that I want to rollback to.
Once you'd identified the ref you want to revert to, you can do so with [git
reset][gitbook-reset]:
```console
$ git reset --hard 13bea0e
HEAD is now at 13bea0e test commit for docs.
```
:::{important}
`git reset --hard <commit>` will discard all changes in your
working directory and index since the commit you're resetting to with
`<commit>`. _This is the main way you can lose work in Git_. If you need
to keep any changes that are in your working directory or that you have
committed, use `git reset --merge <commit>` instead.
:::
You can also use the relative reflog `HEAD@{1}` instead of the commit hash,
just keep in mind that this changes as you run Git commands.
Now when you look at the output of `git reflog`, you should see that the tip of your branch points to your
last commit `13bea0e` before the merge:
```console
$ git reflog
13bea0e HEAD@{2}: reset: moving to HEAD@{1}
e5f8211 HEAD@{3}: pull upstream main: Merge made by the 'recursive' strategy.
13bea0e HEAD@{4}: commit: test commit for docs.
```
And the first entry `git log` shows is this:
```console
commit 13bea0e40197b1670e927a9eb05aaf50df9e8277
Author: Christie Koehler <ck@christi3k.net>
Date: Mon Oct 10 13:25:38 2016 -0700
test commit for docs.
```
## Restore a lost commit
We've mentioned you can use `git reset --hard` to rollback to a previous
commit. What if you run `git reset --hard` and then realize you actually need
one or more of the commits you just discarded? No problem, you can restore them
with `git cherry-pick` ([docs][gitbook-git-cherry-pick]).
For example, let's say you just committed "some work" and your `git log` looks
like this:
```console
* 67aea58 (HEAD -> main) some work
* 13bea0e test commit for docs.
```
You then mistakenly run `git reset --hard 13bea0e`:
```console
$ git reset --hard 13bea0e
HEAD is now at 13bea0e test commit for docs.
$ git log
* 13bea0e (HEAD -> main) test commit for docs.
```
And then realize you actually needed to keep commit 67aea58. First, use
`git reflog` to confirm that commit you want to restore and then run
`git cherry-pick <commit>`:
```console
$ git reflog
13bea0e HEAD@{0}: reset: moving to 13bea0e
67aea58 HEAD@{1}: commit: some work
$ git cherry-pick 67aea58
[main 67aea58] some work
Date: Thu Oct 13 11:51:19 2016 -0700
1 file changed, 1 insertion(+)
create mode 100644 test4.txt
```
## Recover from a `git rebase` failure
One situation in which `git rebase` will fail and require you to intervene is
when your change, which Git will try to re-apply on top of new commits from
which ever branch you are rebasing on top of, is to code that has been changed
by those new commits.
For example, while I'm working on a file, another contributor makes a change to
that file, submits a pull request and has their code merged into `main`.
Usually this is not a problem, but in this case the other contributor made a
change to a part of the file I also want to change. When I try to bring my
branch up to date with `git fetch` and then `git rebase upstream/main`, I see
the following:
```console
First, rewinding head to replay your work on top of it...
Applying: test change for docs
Using index info to reconstruct a base tree...
M README.md
Falling back to patching base and 3-way merge...
Auto-merging README.md
CONFLICT (content): Merge conflict in README.md
error: Failed to merge in the changes.
Patch failed at 0001 test change for docs
The copy of the patch that failed is found in: .git/rebase-apply/patch
When you have resolved this problem, run "git rebase --continue".
If you prefer to skip this patch, run "git rebase --skip" instead.
To check out the original branch and stop rebasing, run "git rebase --abort".
```
This message tells me that Git was not able to apply my changes to README.md
after bringing in the new commits from upstream/main.
Running `git status` also gives me some information:
```console
rebase in progress; onto 5ae56e6
You are currently rebasing branch 'docs-test' on '5ae56e6'.
(fix conflicts and then run "git rebase --continue")
(use "git rebase --skip" to skip this patch)
(use "git rebase --abort" to check out the original branch)
Unmerged paths:
(use "git reset HEAD <file>..." to unstage)
(use "git add <file>..." to mark resolution)
both modified: README.md
no changes added to commit (use "git add" and/or "git commit -a")
```
To fix, open all the files with conflicts in your editor and decide which edits
should be applied. Git uses standard conflict-resolution (`<<<<<<<`, `=======`,
and `>>>>>>>`) markers to indicate where in files there are conflicts.
Tip: You can see recent changes made to a file by running the following
commands:
```bash
git fetch upstream
git log -p upstream/main -- /path/to/file
```
You can use this to compare the changes that you have made to a file with the
ones in upstream, helping you avoid undoing changes from a previous commit when
you are rebasing.
Once you've done that, save the file(s), stage them with `git add` and then
continue the rebase with `git rebase --continue`:
```console
$ git add README.md
$ git rebase --continue
Applying: test change for docs
```
For help resolving merge conflicts, see [basic merge
conflicts][gitbook-basic-merge-conflicts], [advanced
merging][gitbook-advanced-merging], and/or GitHub's help on [how to resolve a
merge conflict][github-help-resolve-merge-conflict].
## Working from multiple computers
Working from multiple computers with Zulip and Git is fine, but you'll need to
pay attention and do a bit of work to ensure all of your work is readily
available.
Recall that most Git operations are local. When you commit your changes with
`git commit` they are safely stored in your _local_ Git database only. That is,
until you _push_ the commits to GitHub, they are only available on the computer
where you committed them.
So, before you stop working for the day, or before you switch computers, push
all of your commits to GitHub with `git push`:
```console
$ git push origin <branchname>
```
When you first start working on a new computer, you'll [clone the Zulip
repository][clone-to-your-machine] and [connect it to Zulip
upstream][connect-upstream]. A clone retrieves all current commits,
including the ones you pushed to GitHub from your other computer.
But if you're switching to another computer on which you have already cloned
Zulip, you need to update your local Git database with new refs from your
GitHub fork. You do this with `git fetch`:
```console
$ git fetch <username>
```
Ideally you should do this before you have made any commits on the same branch
on the second computer. Then you can `git merge` on whichever branch you need
to update:
```console
$ git checkout <my-branch>
Switched to branch '<my-branch>'
$ git merge origin/main
```
**If you have already made commits on the second computer that you need to
keep,** you'll need to use `git log FETCH_HEAD` to identify that hashes of the
commits you want to keep and then `git cherry-pick <commit>` those commits into
whichever branch you need to update.
[clone-to-your-machine]: cloning.md#step-1b-clone-to-your-machine
[connect-upstream]: cloning.md#step-1c-connect-your-fork-to-zulip-upstream
[gitbook-advanced-merging]: https://git-scm.com/book/en/v2/Git-Tools-Advanced-Merging#_advanced_merging
[gitbook-basic-merge-conflicts]: https://git-scm.com/book/en/v2/Git-Branching-Basic-Branching-and-Merging#Basic-Merge-Conflicts
[gitbook-git-cherry-pick]: https://git-scm.com/docs/git-cherry-pick
[gitbook-reset]: https://git-scm.com/docs/git-reset
[github-help-resolve-merge-conflict]: https://help.github.com/en/articles/resolving-a-merge-conflict-using-the-command-line

457
docs/git/using.md Normal file
View File

@@ -0,0 +1,457 @@
# Using Git as you work
## Know what branch you're working on
When using Git, it's important to know which branch you currently have checked
out because most Git commands implicitly operate on the current branch. You can
determine the currently checked out branch several ways.
One way is with [git status][gitbook-git-status]:
```console
$ git status
On branch issue-demo
nothing to commit, working directory clean
```
Another is with [git branch][gitbook-git-branch] which will display all local
branches, with a star next to the current branch:
```console
$ git branch
* issue-demo
main
```
To see even more information about your branches, including remote branches,
use `git branch -vva`:
```console
$ git branch -vva
* issue-123 517468b troubleshooting tip about provisioning
main f0eaee6 [origin/main] bug: Fix traceback in get_missed_message_token_from_address().
remotes/origin/HEAD -> origin/main
remotes/origin/issue-1234 4aeccb7 Another test commit, with longer message.
remotes/origin/main f0eaee6 bug: Fix traceback in get_missed_message_token_from_address().
remotes/upstream/main dbeab6a Optimize checks of test database state by moving into Python.
```
You can also configure [Bash][gitbook-other-envs-bash] and
[Zsh][gitbook-other-envs-zsh] to display the current branch in your prompt.
## Keep your fork up to date
You'll want to [keep your fork][github-help-sync-fork] up-to-date with changes
from Zulip's main repositories.
**Note about `git pull`**: You might be used to using `git pull` on other
projects. With Zulip, because we don't use merge commits, you'll want to avoid
it. Rather than using `git pull`, which by default is a shortcut for
`git fetch && git merge FETCH_HEAD` ([docs][gitbook-git-pull]), you
should use `git fetch` and then `git rebase`.
First, [fetch][gitbook-fetch] changes from Zulip's upstream repository you
configured in the step above:
```console
$ git fetch upstream
```
Next, check out your `main` branch and [rebase][gitbook-git-rebase] it on top
of `upstream/main`:
```console
$ git checkout main
Switched to branch 'main'
$ git rebase upstream/main
```
This will rollback any changes you've made to `main`, update it from
`upstream/main`, and then re-apply your changes. Rebasing keeps the commit
history clean and readable.
When you're ready, [push your changes][github-help-push] to your remote fork.
Make sure you're in branch `main` and then run `git push`:
```console
$ git checkout main
$ git push origin main
```
You can keep any branch up to date using this method. If you're working on a
feature branch (see next section), which we recommend, you would change the
command slightly, using the name of your `feature-branch` rather than `main`:
```console
$ git checkout feature-branch
Switched to branch 'feature-branch'
$ git rebase upstream/main
$ git push origin feature-branch
```
## Work on a feature branch
One way to keep your work organized is to create a branch for each issue or
feature. Recall from [how Git is different][how-git-is-different] that
**Git is designed for lightweight branching and merging.** You can and should
create as many branches as you'd like.
First, make sure your `main` branch is up-to-date with Zulip upstream ([see
how][zulip-git-guide-up-to-date]).
Next, from your `main` branch, create a new tracking branch, providing a
descriptive name for your feature branch:
```console
$ git checkout main
Switched to branch 'main'
$ git checkout -b issue-1755-fail2ban
Switched to a new branch 'issue-1755-fail2ban'
```
Alternatively, you can create a new branch explicitly based off
`upstream/main`:
```console
$ git checkout -b issue-1755-fail2ban upstream/main
Switched to a new branch 'issue-1755-fail2ban'
```
Now you're ready to work on the issue or feature.
## Run linters and tests locally
In addition to having GitHub Actions run tests and linters each time you
push a new commit, you can also run them locally. See
[testing](../testing/testing.md) for details.
## Stage changes
Recall that files tracked with Git have three possible states:
committed, modified, and staged.
To prepare a commit, first add the files with changes that you want
to include in your commit to your staging area. You _add_ both new files and
existing ones. You can also remove files from staging when necessary.
### Get status of working directory
To see what files in the working directory have changes that have not been
staged, use `git status`.
If you have no changes in the working directory, you'll see something like
this:
```console
$ git status
On branch issue-123
nothing to commit, working directory clean
```
If you have unstaged changes, you'll see something like this:
```console
On branch issue-123
Untracked files:
(use "git add <file>..." to include in what will be committed)
newfile.py
nothing added to commit but untracked files present (use "git add" to track)
```
### Stage additions with `git add`
To add changes to your staging area, use `git add <filename>`. Because
`git add` is all about staging the changes you want to commit, you use
it to add _new files_ as well as _files with changes_ to your staging
area.
Continuing our example from above, after we run `git add newfile.py`, we'll see
the following from `git status`:
```console
On branch issue-123
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: newfile.py
```
You can view the changes in files you have staged with `git diff --cached`. To
view changes to files you haven't yet staged, just use `git diff`.
If you want to add all changes in the working directory, use `git add -A`
([documentation][gitbook-add]).
You can also stage changes using your graphical Git client.
If you stage a file, you can undo it with `git reset HEAD <filename>`. Here's
an example where we stage a file `test3.txt` and then unstage it:
```console
$ git add test3.txt
On branch issue-1234
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: test3.txt
$ git reset HEAD test3.txt
$ git status
On branch issue-1234
Untracked files:
(use "git add <file>..." to include in what will be committed)
test3.txt
nothing added to commit but untracked files present (use "git add" to track)
```
### Stage deletions with `git rm`
To remove existing files from your repository, use `git rm`
([documentation][gitbook-rm]). This command can either stage the file for
removal from your repository AND delete it from your working directory or just
stage the file for deletion and leave it in your working directory.
To stage a file for deletion and **remove** it from your working directory, use
`git rm <filename>`:
```console
$ git rm test.txt
rm 'test.txt'
$ git status
On branch issue-1234
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
deleted: test.txt
$ ls test.txt
ls: No such file or directory
```
To stage a file for deletion and **keep** it in your working directory, use
`git rm --cached <filename>`:
```console
$ git rm --cached test2.txt
rm 'test2.txt'
$ git status
On branch issue-1234
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
deleted: test2.txt
$ ls test2.txt
test2.txt
```
If you stage a file for deletion with the `--cached` option, and haven't yet
run `git commit`, you can undo it with `git reset HEAD <filename>`:
```console
$ git reset HEAD test2.txt
```
Unfortunately, you can't restore a file deleted with `git rm` if you didn't use
the `--cache` option. However, `git rm` only deletes files it knows about.
Files you have never added to Git won't be deleted.
## Commit changes
When you've staged all your changes, you're ready to commit. You can do this
with `git commit -m "My commit message."` to include a commit message.
Here's an example of committing with the `-m` for a one-line commit message:
```console
$ git commit -m "Add a test commit for docs."
[issue-123 173e17a] Add a test commit for docs.
1 file changed, 1 insertion(+)
create mode 100644 newfile.py
```
You can also use `git commit` without the `-m` option and your editor to open,
allowing you to easily draft a multi-line commit message.
How long your commit message should be depends on where you are in your work.
Using short, one-line messages for commits related to in-progress work makes
sense. For a commit that you intend to be final or that encompasses a
significant amount or complex work, you should include a longer message.
Keep in mind that your commit should contain a 'minimal coherent idea' and have
a quality commit message. See Zulip docs [Commit
Discipline][zulip-rtd-commit-discipline] and [Commit
messages][zulip-rtd-commit-messages] for details.
Here's an example of a longer commit message that will be used for a pull request:
```text
Integrate Fail2Ban.
Updates Zulip logging to put an unambiguous entry into the logs such
that fail2ban can be configured to look for these entries.
Tested on my local Ubuntu development server, but would appreciate
someone testing on a production install with more users.
Fixes #1755.
```
The first line is the summary. It's a complete sentence, ending in a period. It
uses a present-tense action verb, "Integrate", rather than "Integrates" or
"Integrating".
The following paragraphs are full prose and explain why and how the change was
made. It explains what testing was done and asks specifically for further
testing in a more production-like environment.
The final paragraph indicates that this commit addresses and fixes issue #1755.
When you submit your pull request, GitHub will detect and link this reference
to the appropriate issue. Once your commit is merged into `upstream/main`, GitHub
will automatically close the referenced issue. See [Closing issues via commit
messages][github-help-closing-issues] for details.
Note in particular that GitHub's regular expressions for this feature
are sloppy, so phrases like `Partially fixes #1234` will automatically
close the issue. Phrases like `Fixes part of #1234` are a good
alternative.
Make as many commits as you need to address the issue or implement your feature.
## Push your commits to GitHub
As you're working, it's a good idea to frequently push your changes to GitHub.
This ensures your work is backed up should something happen to your local
machine and allows others to follow your progress. It also allows you to
[work from multiple computers][self-multiple-computers] without losing work.
Pushing to a feature branch is just like pushing to `main`:
```console
$ git push origin <branch-name>
Counting objects: 6, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (4/4), done.
Writing objects: 100% (6/6), 658 bytes | 0 bytes/s, done.
Total 6 (delta 3), reused 0 (delta 0)
remote: Resolving deltas: 100% (3/3), completed with 1 local objects.
To git@github.com:christi3k/zulip.git
* [new branch] issue-demo -> issue-demo
```
If you want to see what Git will do without actually performing the push, add
the `-n` (dry-run) option: `git push -n origin <branch-name>`. If everything
looks good, re-run the push command without `-n`.
If the feature branch does not already exist on GitHub, it will be created when
you push and you'll see `* [new branch]` in the command output.
## Examine and tidy your commit history
Examining your commit history prior to submitting your pull request is a good
idea. Is it tidy such that each commit represents a minimally coherent idea
(see [commit discipline][zulip-rtd-commit-discipline])? Do your commit messages
follow [Zulip's style][zulip-rtd-commit-messages]? Will the person reviewing
your commit history be able to clearly understand your progression of work?
On the command line, you can use the `git log` command to display an easy to
read list of your commits:
```console
$ git log --all --graph --oneline --decorate
* 4f8d75d (HEAD -> 1754-docs-add-git-workflow) docs: Add details about configuring Travis CI.
* bfb2433 (origin/1754-docs-add-git-workflow) docs: Add section for keeping fork up-to-date to Git Guide.
* 4fe10f8 docs: Add sections for creating and configuring fork to Git Guide.
* 985116b docs: Add graphic client recs to Git Guide.
* 3c40103 docs: Add stubs for remaining Git Guide sections.
* fc2c01e docs: Add git guide quickstart.
| * f0eaee6 (upstream/main) bug: Fix traceback in get_missed_message_token_from_address().
```
Alternatively, use your graphical client to view the history for your feature branch.
If you need to update any of your commits, you can do so with an interactive
[rebase][github-help-rebase]. Common reasons to use an interactive rebase
include:
- squashing several commits into fewer commits
- splitting a single commit into two or more
- rewriting one or more commit messages
There is ample documentation on how to rebase, so we won't go into details
here. We recommend starting with GitHub's help article on
[rebasing][github-help-rebase] and then consulting Git's documentation for
[git-rebase][gitbook-git-rebase] if you need more details.
If all you need to do is edit the commit message for your last commit, you can
do that with `git commit --amend`. See [Git Basics - Undoing
Things][gitbook-basics-undoing] for details on this and other useful commands.
## Force-push changes to GitHub after you've altered your history
Any time you alter history for commits you have already pushed to GitHub,
you'll need to prefix the name of your branch with a `+`. Without this, your
updates will be rejected with a message such as:
```console
$ git push origin 1754-docs-add-git-workflow
To git@github.com:christi3k/zulip.git
! [rejected] 1754-docs-add-git-workflow -> 1754-docs-add-git-workflow (non-fast-forward)
error: failed to push some refs to 'git@github.com:christi3k/zulip.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.,
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.
```
Re-running the command with `+<branch>` allows the push to continue by
re-writing the history for the remote repository:
```console
$ git push origin +1754-docs-add-git-workflow
Counting objects: 12, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (12/12), done.
Writing objects: 100% (12/12), 3.71 KiB | 0 bytes/s, done.
Total 12 (delta 8), reused 0 (delta 0)
remote: Resolving deltas: 100% (8/8), completed with 2 local objects.
To git@github.com:christi3k/zulip.git
+ 2d49e2d...bfb2433 1754-docs-add-git-workflow -> 1754-docs-add-git-workflow (forced update)
```
This is perfectly okay to do on your own feature branches, especially if you're
the only one making changes to the branch. If others are working along with
you, they might run into complications when they retrieve your changes because
anyone who has based their changes off a branch you rebase will have to do a
complicated rebase.
[gitbook-add]: https://git-scm.com/docs/git-add
[gitbook-basics-undoing]: https://git-scm.com/book/en/v2/Git-Basics-Undoing-Things
[gitbook-fetch]: https://git-scm.com/docs/git-fetch
[gitbook-git-branch]: https://git-scm.com/docs/git-branch
[gitbook-git-pull]: https://git-scm.com/docs/git-pull
[gitbook-git-rebase]: https://git-scm.com/docs/git-rebase
[gitbook-git-status]: https://git-scm.com/docs/git-status
[gitbook-other-envs-bash]: https://git-scm.com/book/en/v2/Appendix-A%3A-Git-in-Other-Environments-Git-in-Bash
[gitbook-other-envs-zsh]: https://git-scm.com/book/en/v2/Appendix-A%3A-Git-in-Other-Environments-Git-in-Zsh
[gitbook-rm]: https://git-scm.com/docs/git-rm
[github-help-closing-issues]: https://help.github.com/en/articles/closing-issues-via-commit-messages
[github-help-push]: https://help.github.com/en/articles/pushing-to-a-remote
[github-help-rebase]: https://help.github.com/en/articles/using-git-rebase
[github-help-sync-fork]: https://help.github.com/en/articles/syncing-a-fork
[how-git-is-different]: the-git-difference.md
[self-multiple-computers]: troubleshooting.md#working-from-multiple-computers
[zulip-git-guide-up-to-date]: #keep-your-fork-up-to-date
[zulip-rtd-commit-discipline]: ../contributing/commit-discipline.md
[zulip-rtd-commit-messages]: ../contributing/commit-discipline.md

View File

@@ -0,0 +1,50 @@
# Working copies
When you work on Zulip code, there are three copies of the Zulip Git
repository that you are generally concerned with:
- The `upstream` remote. This is the [official Zulip
repository](https://github.com/zulip/zulip) on GitHub. You probably
don't have write access to this repository.
- The **origin** remote: Your personal remote repository on GitHub.
You'll use this to share your code and create [pull requests](pull-requests.md).
- local copy: This lives on your laptop or your remote dev instance,
and is what you'll use to make changes and create commits.
When you work on Zulip code, you will end up moving code between
the various working copies.
## Workflows
Sometimes you need to get commits. Here are some scenarios:
- You may fork the official Zulip repository to your GitHub fork.
- You may fetch commits from the official Zulip repository to your local copy.
- You occasionally may fetch commits from your forked copy.
Sometimes you want to publish commits. Here are some scenarios:
- You push code from your local copy to your GitHub fork. (You usually
want to put the commit on a feature branch.)
- You submit a PR to the official Zulip repo.
Finally, the Zulip core team will occasionally want your changes!
- The Zulip core team can accept your changes and add them to
the official repo, usually on the `main` branch.
## Relevant Git commands
The following commands are useful for moving commits between
working copies:
- `git fetch`: This grabs code from another repository to your local
copy. (Defaults to fetching from your default remote, `origin`).
- `git fetch upstream`: This grabs code from the upstream repository to your local copy.
- `git push`: This pushes code from your local repository to one of the remotes.
- `git remote`: This helps you configure short names for remotes.
- `git pull`: This pulls code, but by default creates a merge commit
(which you definitely don't want). However, if you've followed our
[cloning documentation](cloning.md), this will do
`git pull --rebase` instead, which is the only mode you'll want to
use when working on Zulip.

180
docs/git/zulip-tools.md Normal file
View File

@@ -0,0 +1,180 @@
# Zulip-specific tools
This article documents several useful tools that can save you a lot of
time when working with Git on the Zulip project.
## Set up Git repo script
**Extremely useful**. In the `tools` directory of
[zulip/zulip][github-zulip-zulip] you'll find a bash script
`setup-git-repo`. This script installs a pre-commit hook, which will
run each time you `git commit` to automatically run
[Zulip's linter suite](../testing/linters.md) on just the files that
the commit modifies (which is really fast!). The hook passes no matter
the result of the linter, but you should still pay attention to any
notices or warnings it displays.
It's simple to use. Make sure you're in the clone of zulip and run the following:
```console
$ ./tools/setup-git-repo
```
The script doesn't produce any output if successful. To check that the hook has
been installed, print a directory listing for `.git/hooks` and you should see
something similar to:
```console
$ ls -l .git/hooks
pre-commit -> ../../tools/pre-commit
```
## Configure continuous integration for your Zulip fork
You might also wish to [configure continuous integration for your fork][zulip-git-guide-ci].
## Reset to pull request
`tools/reset-to-pull-request` is a short-cut for [checking out a pull request
locally][zulip-git-guide-fetch-pr]. It works slightly differently from the method
described above in that it does not create a branch for the pull request
checkout.
**This tool checks for uncommitted changes, but it will move the
current branch using `git reset --hard`. Use with caution.**
First, make sure you are working in a branch you want to move (in this
example, we'll use the local `main` branch). Then run the script
with the ID number of the pull request as the first argument.
```console
$ git checkout main
Switched to branch 'main'
Your branch is up-to-date with 'origin/main'.
$ ./tools/reset-to-pull-request 1900
+ request_id=1900
+ git fetch upstream pull/1900/head
remote: Counting objects: 159, done.
remote: Compressing objects: 100% (17/17), done.
remote: Total 159 (delta 94), reused 91 (delta 91), pack-reused 51
Receiving objects: 100% (159/159), 55.57 KiB | 0 bytes/s, done.
Resolving deltas: 100% (113/113), completed with 54 local objects.
From https://github.com/zulip/zulip
* branch refs/pull/1900/head -> FETCH_HEAD
+ git reset --hard FETCH_HEAD
HEAD is now at 2bcd1d8 troubleshooting tip about provisioning
```
## Fetch a pull request and rebase
`tools/fetch-rebase-pull-request` is a short-cut for [checking out a pull
request locally][zulip-git-guide-fetch-pr] in its own branch and then updating it with any
changes from `upstream/main` with `git rebase`.
Run the script with the ID number of the pull request as the first argument.
```console
$ tools/fetch-rebase-pull-request 1913
+ request_id=1913
+ git fetch upstream pull/1913/head
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 4 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (4/4), done.
From https://github.com/zulip/zulip
* branch refs/pull/1913/head -> FETCH_HEAD
+ git checkout upstream/main -b review-1913
Branch review-1913 set up to track remote branch main from upstream.
Switched to a new branch 'review-1913'
+ git reset --hard FETCH_HEAD
HEAD is now at 99aa2bf Add provision.py fails issue in common errors
+ git pull --rebase
Current branch review-1913 is up to date.
```
## Fetch a pull request without rebasing
`tools/fetch-pull-request` is a similar to `tools/fetch-rebase-pull-request`, but
it does not rebase the pull request against `upstream/main`, thereby getting
exactly the same repository state as the commit author had.
Run the script with the ID number of the pull request as the first argument.
```console
$ tools/fetch-pull-request 5156
+ git diff-index --quiet HEAD
+ request_id=5156
+ remote=upstream
+ git fetch upstream pull/5156/head
From https://github.com/zulip/zulip
* branch refs/pull/5156/head -> FETCH_HEAD
+ git checkout -B review-original-5156
Switched to a new branch 'review-original-5156'
+ git reset --hard FETCH_HEAD
HEAD is now at 5a1e982 tools: Update clean-branches to clean review branches.
```
## Push to a pull request
`tools/push-to-pull-request` is primarily useful for maintainers who
are merging other users' commits into a Zulip repository. After doing
`reset-to-pull-request` or `fetch-pull-request` and making some
changes, you can push a branch back to a pull request with, for example,
`tools/push-to-pull-request 1234`. This is useful for a few things:
- Getting CI to run and enabling you to use the GitHub "Merge" buttons
to merge a PR after you make some corrections to a PR, without
waiting for an extra round trip with the PR author.
- For commits that aren't ready to merge yet, communicating clearly
any changes you'd like to see happen that are easier for you to
explain by just editing the code than in words.
- Saving a contributor from needing to duplicate any rebase work that
you did as part of integrating parts of the PR.
You'll likely want to comment on the PR after doing so, to ensure that
the original contributor knows to pull your changes rather than
accidentally overwriting them with a force push when they make their
next batch of changes.
Note that in order to do this you need permission to do such a push,
which GitHub offers by default to users with write access to the
repository. For multiple developers collaborating on a PR, you can
achieve this by granting other users permission to write to your fork.
## Delete unimportant branches
`tools/clean-branches` is a shell script that removes branches that are either:
1. Local branches that are ancestors of `origin/main`.
2. Branches in origin that are ancestors of `origin/main` and named like `$USER-*`.
3. Review branches created by `tools/fetch-rebase-pull-request` and `tools/fetch-pull-request`.
First, make sure you are working in branch `main`. Then run the script without any
arguments for default behavior. Since removing review branches can inadvertently remove any
feature branches whose names are like `review-*`, it is not done by default. To
use it, run `tools/clean-branches --reviews`.
```console
$ tools/clean-branches --reviews
Deleting local branch review-original-5156 (was 5a1e982)
```
## Merge conflict on `pnpm-lock.yaml` file
If there is a merge conflict on `pnpm-lock.yaml`, pnpm should be run to
regenerate the file. _Important:_ don't delete the `pnpm-lock.yaml` file. Check out the
latest one from `origin/main` so that pnpm knows the previous asset versions.
Run the following commands
```bash
git checkout origin/main -- pnpm-lock.yaml
pnpm install
git add pnpm-lock.yaml
git rebase --continue
```
[github-zulip-zulip]: https://github.com/zulip/zulip/
[zulip-git-guide-fetch-pr]: collaborate.md#check-out-a-pull-request-locally
[zulip-git-guide-ci]: cloning.md#step-3-configure-continuous-integration-for-your-fork