mirror of
https://github.com/apple/swift.git
synced 2025-12-25 12:15:36 +01:00
This document describes the current git workflow that is meant to be used when developing for the swift project. At some point in the future, we may discuss changing from this rebase based workflow to a merge based workflow.
280 lines
9.5 KiB
ReStructuredText
280 lines
9.5 KiB
ReStructuredText
:orphan:
|
||
|
||
Git Workflows
|
||
=============
|
||
|
||
Purpose
|
||
-------
|
||
|
||
Swift development has been based on SVN since its inception. As part of the
|
||
transition to Git this document helps to address questions about how common SVN
|
||
workflows we use today translate to their Git counterparts as well as to discuss
|
||
Git workflow practices we plan on having — at least initially — after the Git
|
||
transition. Notably we will follow a model where commits to trunk — which is
|
||
the ‘master’ branch in Git — has commits land (in the common case) via rebasing
|
||
instead of merging. This model is open to evolution later, but this mimics the
|
||
workflow we have today with SVN.
|
||
|
||
SVN -> GIT Workflows
|
||
====================
|
||
|
||
The general SVN workflow consists of the following commands:
|
||
|
||
1. Checkout: This means checking out/setting up a new repository.
|
||
2. Update: Pulling the latest remote changes into a local repository.
|
||
3. Commiting: Committing a change to the remote repository.
|
||
4. Reverting: Reverting a change from a remote repository.
|
||
5. Browsing: Looking at commits.
|
||
|
||
This document will show how to translate these commands to Git and additionally
|
||
how to configure Git. It assumes that one is attempting to manipulate a Git
|
||
repository via bash in a terminal. A lot of information since this is supposed
|
||
to be a short, actionable guide. For more information, please see the Git crash
|
||
course guide for SVN users at <https://git-scm.com/course/SVN.html>
|
||
|
||
*NOTE* When ever when we say the Swift repository we mean any repository in the
|
||
Swift project.
|
||
|
||
Quicksetup (TLDR)
|
||
-----------------
|
||
|
||
For those who do not want to read the full document, use the following commands
|
||
to perform a simple repo setup for the Swift repository::
|
||
|
||
$ git config --global user.name "<My Name>"
|
||
$ git config --global user.email "<My Email>"
|
||
$ mkdir swift-source && cd swift-soure
|
||
$ git clone <LLVM_REPO_URL>
|
||
$ git clone <CLANG_REPO_URL>
|
||
$ git clone <SWIFT_REPO_URL>
|
||
$ (cd swift && git config branch.autosetuprebase always)
|
||
$ git clone <CMARK_REPO_URL>
|
||
$ git clone <NINJA_REPO_URL>
|
||
|
||
Then to commit a new commit to the remote swift repository::
|
||
|
||
$ git commit
|
||
$ git push origin master
|
||
|
||
and to pull new commits from the remote swift repository::
|
||
|
||
$ git pull origin master
|
||
|
||
In order to ease updating all repositories, consider using the script in
|
||
'./utils/update-checkout'. This will automate updating the repositories in the
|
||
proper way.
|
||
|
||
Preliminary
|
||
-----------
|
||
|
||
Before beginning, we need to perform some global configuration of Git. Git
|
||
includes a username/email of the committer in every commit. By default this is
|
||
the current logged in user and the hostname of the machine. This is /not/ what
|
||
one wants. We configure Git globally (i.e. across all repositories) to have our
|
||
proper name and email by running the following commands::
|
||
|
||
$ git config --global user.name "<My Name>"
|
||
$ git config --global user.email "<My Email>"
|
||
|
||
Checkout
|
||
--------
|
||
|
||
Normally if one wishes to checkout a repository in SVN, one would use a command
|
||
like this::
|
||
|
||
$ SVN co <repository url> <local directory>
|
||
|
||
This would then checkout the latest revision from the repository specified by
|
||
'repository url' and place it into the directory 'local directory'. In Git,
|
||
instead of checking out the repository, one clones the repository. This is done
|
||
as follows::
|
||
|
||
$ git clone <repository url> <local directory>
|
||
|
||
This will cause Git to clone the repository at 'repository url' and check out
|
||
the 'master' branch. The 'master' branch corresponds to 'trunk' in SVN. For more
|
||
information about branching in Git please see
|
||
<https://git-scm.com/course/SVN.html#branch>
|
||
|
||
Before beginning to commit though, we /must/ perform some default configuration
|
||
of our repository to match the Swift repository default configuration by
|
||
enabling default rebasing.
|
||
|
||
Repository Configuration (Enabling Default Rebasing)
|
||
----------------------------------------------------
|
||
|
||
Once we have cloned the repository, we need to configure the repository for our
|
||
use. Specifically we want to configure the swift repository so that we rebase
|
||
whenever we update the repository (see the update section below for more
|
||
details)::
|
||
|
||
$ git config branch.autosetuprebase always
|
||
|
||
By default when updating, Git will attempt to merge the remote changes and your
|
||
local changes. Ignoring what that sentence means, this is not an SVN-esque
|
||
model. Instead we want any local changes that we have to be applied on top of
|
||
any new remote changes. The 'branch.autosetuprebase' flag causes this to be done
|
||
automatically when ever one updates the local repository.
|
||
|
||
Update
|
||
------
|
||
|
||
In SVN, one updates your local repository by running the update command::
|
||
|
||
$ SVN update
|
||
|
||
In Git, instead of performing SVN update, one pulls from the remote repository::
|
||
|
||
$ git pull --rebase origin master
|
||
|
||
This will pull any new remote commits into your local repository and then replay
|
||
your current local commits ontop of those new commits.
|
||
|
||
By default the '--rebase' flag is not necessary for the Swift repository because
|
||
it is configured to always rebase by setting the 'branch.autosetuprebase' flag
|
||
(see the section 'Repository Configuration (Enabling Default Rebasing)' above).
|
||
|
||
Commit
|
||
------
|
||
|
||
In SVN, committing always means submitting changes to a remote repository. In
|
||
Git, committing refers to the process of first telling Git to track a change by
|
||
staging the change and then commiting all staged changes into a change in the
|
||
local repository. One can have many such commits. Then when one is ready, one
|
||
pushes the new local changes to the remote repository. We go through these steps
|
||
in more detail below:
|
||
|
||
In terms of replicating the SVN model, there are now two steps. In order to
|
||
commit changes one first stages a changed file using 'git add'::
|
||
|
||
$ git add <path>
|
||
|
||
Then once all changes that you want to be apart of the commit have been staged,
|
||
a commit is created in the local repository via the 'commit' command::
|
||
|
||
$ git commit
|
||
|
||
As a shortcut to commit /all/ changes to local files that are already being
|
||
tracked by Git to the local repository, you can use the '-a' command::
|
||
|
||
$ git commit -a
|
||
|
||
In both of these cases, an editor will pop up to accept a commit message. To
|
||
specify a short commit message at the commandline, you can use the '-m' flag::
|
||
|
||
$ git commit -m 'My great commit message.'
|
||
|
||
In order to see the diff of changes that have not been staged, run the command::
|
||
|
||
$ git diff
|
||
|
||
To see all changes that have been staged, run the command::
|
||
|
||
$ git diff --staged
|
||
|
||
To get a diff for a specific revision/path, perform the following command::
|
||
|
||
$ git diff <revision> <path>
|
||
|
||
In order to get a more concise view of the files that have staged and or
|
||
unstaged changes, run the command::
|
||
|
||
$ git status
|
||
|
||
In order to restore a file from the last revision, one uses the checkout
|
||
command::
|
||
|
||
$ git checkout <path>
|
||
|
||
To restore a file to a specific revision, one must use a longer form of the
|
||
command::
|
||
|
||
$ git checkout <revision> -- <path>
|
||
|
||
To unstage a file, one uses the 'reset' command::
|
||
|
||
$ git reset <path>
|
||
|
||
This tells Git to reset '<path>' in the staging area to the top of tree commit
|
||
(which in Git is called 'HEAD'). In order to correct a mistake, you can pass the
|
||
'amend' flag to Git::
|
||
|
||
$ git commit --amend
|
||
|
||
This will cause all staged changes to be merged into 'HEAD'. Once one has made
|
||
all the relevant commits, in order to push the changes to the remote repository
|
||
the 'push' command is used::
|
||
|
||
$ git push origin master
|
||
|
||
If a different committer has committed changes such that there are remote
|
||
commits that are not present locally, this will fail. In order to get around
|
||
this issue, perform::
|
||
|
||
$ git pull --rebase origin master
|
||
|
||
in order to pull the new remote commits and replay your new commits on top. Then
|
||
try to push again. See the 'Checkout' section above how to configure the local
|
||
swift repository to always rebase allowing you to drop the '--rebase' flag.
|
||
|
||
Revert
|
||
------
|
||
|
||
In SVN reverting a commit implies performing a reverse merge. In Git, this is no
|
||
longer true. Instead one now just uses the 'revert' command::
|
||
|
||
$ git revert <revision>
|
||
|
||
This will cause Git to perform the reverse merge of that revision for you
|
||
against HEAD and bring up a message window for you to write a commit
|
||
message. This will be autofilled in with the title of the commit that is going
|
||
to be reverted and the revision number of that commit like so::
|
||
|
||
Revert "<FIRST LINE OF REVERTED COMMITS COMMIT MSG>"
|
||
|
||
This reverts commit <REVISION>.
|
||
|
||
One can edit this message as one sees fit. Once this has been done, the revert
|
||
will become a normal commit in your repository like any other commit. Thus to
|
||
revert the commit in the remote repository, you need to perform a Git push::
|
||
|
||
$ git push origin master
|
||
|
||
Browsing
|
||
--------
|
||
|
||
This section explains how one can view Git changes. In order to view a history
|
||
of all changes on a branch to the beginning of time use the 'log' command::
|
||
|
||
$ git log
|
||
|
||
This will for each commit show the following information::
|
||
|
||
commit <REVISION>
|
||
Author: <AUTHOR NAME> <AUTHOR EMAIL>
|
||
Date: <TIMESTAMP>
|
||
|
||
<COMMIT MSG>
|
||
|
||
To see history starting at a specific commit use the following form of a Git log
|
||
command::
|
||
|
||
$ git log <REVISION>
|
||
|
||
To see a oneline summary that includes just the title of the commit and its
|
||
hash, pass the '--oneline' command::
|
||
|
||
$ git log --oneline
|
||
|
||
It will not show you what was actually changed in each commit. In order to see
|
||
what was actually changed in a commit, use the command 'show'::
|
||
|
||
$ git show
|
||
|
||
This will show the aforementioned information shown by Git log, but additionally
|
||
will perform a diff against top of tree showing you the contents of the
|
||
change. To see the changes for a specific commit, pass the revision to Git
|
||
show::
|
||
|
||
$ git show <REVISION>
|