Qt wiki will be updated on October 12th 2023 starting at 11:30 AM (EEST) and the maintenance will last around 2-3 hours. During the maintenance the site will be unavailable.
Git Introduction: Difference between revisions
mNo edit summary |
(Move to new Process sub-category) |
||
(11 intermediate revisions by 4 users not shown) | |||
Line 1: | Line 1: | ||
__TOC__ | __TOC__ | ||
[[Category:Developing Qt::Process]] | |||
This document is a simple guide showing the procedures necessary to develop and maintain patches on top of Qt. It is not a replacement for the Git manual | [[Category:Tutorial]] | ||
This document is a simple guide showing the procedures necessary to develop and maintain patches on top of Qt. | |||
It is not a replacement for the [https://www.git-scm.com/docs Git manual]. | |||
== Git Repositories == | == Git Repositories == | ||
Line 12: | Line 10: | ||
<pre> | <pre> | ||
$ git clone git://code.qt.io/qt/ | $ git clone git://code.qt.io/qt/qt5.git | ||
cd qt | cd qt | ||
</pre> | </pre> | ||
This creates a new directory called | This creates a new directory called "qt5" and downloads the source code into it. | ||
It also downloads the entire history of all files in all versions, therefore creating an identical copy – called a repository – of what is stored on the server. | |||
That is why the process is called cloning. | |||
The source of the clone is remembered as the "origin". | |||
Your clone will initially be checked out on some branch, most likely "dev"; you can use <kbd>git branch -r</kbd> to find out what branches are available – | |||
they'll be listed as <kbd>origin/dev</kbd> and similar; the part after <kbd>origin/</kbd> is the name (here, <kbd>dev</kbd>) of a branch you can now check out. | |||
Pick [[Branch Guidelines|a suitable branch]] for the work you want to do and check it out; | |||
for example, <kbd>git checkout dev</kbd> if you want <kbd>dev</kbd> (to which all new features go). | |||
Once you've cloned the top-level qt5 super-module and selected a suitable branch, | |||
see the <kbd>README.git</kbd> file in it for instructions on how to check out all the sub-modules. | |||
Now that you have all the changes inside the repository, you can work 100% offline. An internet connection is necessary only when you need to fetch new source code changes or push upstream. | You can create new clones simply by copying the directory, for example onto a USB stick. | ||
The new directory will be self-contained, too. | |||
Now that you have all the changes inside the repository, you can work 100% offline. | |||
An internet connection is necessary only when you need to fetch new source code changes or push upstream. | |||
== Inspecting the source code == | == Inspecting the source code == | ||
This section introduces the Git log, show and blame commands to find out the history of the project. | This section introduces the Git log, show and blame commands to find out the history of the project. | ||
You'll usually want to do this for submodules and the files in them; | |||
so <kbd>cd</kbd> into the submodule you want to work in before you run these commands. | |||
Run the log command to view recent changes: | Run the log command to view recent changes: | ||
Line 32: | Line 44: | ||
</pre> | </pre> | ||
This command launches a pager program allowing you to scroll through the list of committed changes with the cursor and Page Up/Down keys. To return to the shell press the 'q' key. | This command launches a pager program allowing you to scroll through the list of committed changes with the cursor and Page Up/Down keys. | ||
To return to the shell press the 'q' key. | |||
The log command accepts options, such as -n to limit the number of changes. For example to list the last three changes run: | The log command accepts options, such as -n to limit the number of changes. For example to list the last three changes run: | ||
Line 44: | Line 57: | ||
<pre> | <pre> | ||
$ git log src/corelib/kernel | $ git log src/corelib/kernel | ||
$ git log src/gui/kernel/ | $ git log src/gui/kernel/qwindow.cpp | ||
$ git log examples/examples.pro examples/painting/basicdrawing/main.cpp | $ git log examples/examples.pro examples/widgets/painting/basicdrawing/main.cpp | ||
</pre> | </pre> | ||
There are various ways | There are various ways to limit the output of the log command, beyond the ones described here. | ||
Refer to [http://www.kernel.org/pub/software/scm/git/docs/git-log.html#_commit_limiting git log's documentation] for more details. | |||
For example, if you're working on a branch based on <kbd>dev</kbd>, passing argument <kbd>dev..</kbd> (i.e. put two dots after the base-branch name) will limit to the changes you've made. | |||
Changes in Git are identified with a unique SHA1 checksum. The checksum is on the first line of the git log output. For example: | Changes in Git are identified with a unique SHA1 checksum. The checksum is on the first line of the git log output. For example (taken from <kbd>qtbase</kbd>): | ||
<pre> | <pre> | ||
commit | commit 019dd88d2cf63ff065bfd801876b213e8193c60f | ||
Author: | Author: Friedemann Kleint <Friedemann.Kleint@qt.io> | ||
Date: | Date: Wed Jul 11 12:59:30 2018 +0200 | ||
QStringView: Add compare() member function | |||
There was no public API for doing case-insensitive comparisons | |||
of QStringView. | |||
Task-number: QTBUG-69389 | |||
Change-Id: I1b021eefec35e135b97fb87704c8dc137232d83d | |||
Reviewed-by: | Reviewed-by: Edward Welbourne <edward.welbourne@qt.io> | ||
Reviewed-by: Thiago Macieira <thiago.macieira@intel.com> | |||
</pre> | </pre> | ||
You can inspect commits using the git show command with the commit id as argument. The following command shows the entire change above including a diff: | You can inspect commits using the <kbd>git show</kbd> command with the commit id as argument. | ||
The following command shows the entire change above including a diff: | |||
<pre> | <pre> | ||
$ git show | $ git show 019dd88d2cf63ff065bfd801876b213e8193c60f | ||
</pre> | </pre> | ||
Line 79: | Line 96: | ||
</pre> | </pre> | ||
To inspect a whole series of commits, | To inspect a whole series of commits, pass <kbd>-p</kbd> to <kbd>git log</kbd>, e.g. | ||
<pre> | <pre> | ||
$ git log -p | $ git log -p dev.. | ||
</pre> | </pre> | ||
The git show and log commands allow you to inspect the history of the project or individual files. Sometimes it is also useful to inspect source code on a line-by-line basis, for example when you would like to find out who introduced a certain snippet of code. Git provides this functionality with the blame command: | The <kbd>git show</kbd> and <kbd>log</kbd> commands allow you to inspect the history of the project or of individual files. | ||
Sometimes it is also useful to inspect source code on a line-by-line basis, for example when you would like to find out who introduced a certain snippet of code. | |||
Git provides this functionality with the <kbd>blame</kbd> command: | |||
<pre> | <pre> | ||
$ git blame src/ | $ git blame src/widgets/kernel/qwidget.cpp | ||
</pre> | </pre> | ||
The output of this command - shown in a pager - | The output of this command - shown in a pager - shows each line of the file with a prefix giving the commit id, followed by the author and date, of the last change affecting that line. | ||
Git specializes in tracking the content of files, the name of a file is less important than the source code it contains. Therefore git blame can automatically detect, for example, that a function was moved from one file to another. | Git specializes in tracking the content of files, the name of a file is less important than the source code it contains. | ||
Therefore <kbd>git blame</kbd> can automatically detect, for example, that a function was moved from one file to another; | |||
so it may attribute lines of your file to commits that changed that line before it was moved to the file it's now in. | |||
== Making changes == | == Making changes == | ||
=== Setting up | You can change your local copy of Qt if you want to try out something different; | ||
usually, you'll want your change integrated upstream. | |||
[[Setting up Gerrit]] explains how to configure git, and how to clone Qt repositories. | |||
=== Setting up to make changes === | |||
The previous sections explained how to clone the repository and how to find out the history of the project. This section finally shows how to create history, | The previous sections explained how to clone the repository and how to find out the history of the project. | ||
This section finally shows how to create history, by recording changes as new commits and tracking commits in branches. | |||
The first step is to identify | The first step is to identify the branch of development on which to base your work. | ||
In Git, branches are a very lightweight concept that allows identifying commits by name. | |||
Each commit has a reference to its parent commit(s), which forms the history. | |||
The <kbd>git branch</kbd> command, without any arguments, displays the list of local branches, with a <kbd>*</kbd> beside the branch currently checked out: | |||
<pre> | <pre> | ||
Line 108: | Line 137: | ||
</pre> | </pre> | ||
The output shows that we have only one local branch called "master" and the "*" indicates that it is the current branch. The name "master" in Git development usually describes the main line of development. | The output shows that we have only one local branch called "master" and the "*" indicates that it is the current branch. | ||
The name "master" in Git development usually describes the main line of development. | |||
(This is used by some sub-modules, like <kbd>qtrepotools</kbd>, and is the usual form of <kbd>git</kbd> repositories. | |||
However, most of Qt's sub-modules, along with the <kbd>qt5</kbd> super-module, have other branch names by default. | |||
We'll stick with <kbd>master</kbd> for this tutorial, but remember you'll usually want to replace it with <kbd>dev</kbd> or some other branch name in practice.) | |||
Besides your local branches Git also remembers the branches in the origin repository. The "-r" option shows them, prefixed with "origin": | Besides your local branches Git also remembers the branches in the origin repository. The "-r" option shows them, prefixed with "origin": | ||
Line 143: | Line 177: | ||
</pre> | </pre> | ||
This will also update the files in your working directory to match the latest commit in the new current branch. New commits will be recorded in "my-feature" instead of the previous "master" branch. | This will also update the files in your working directory to match the latest commit in the new current branch. | ||
New commits will be recorded in "my-feature" instead of the previous "master" branch. | |||
You can have as many local branches as you like, they are very cheap. Each branch uses only few bytes of disk space. Please see the | You can have as many local branches as you like, they are very cheap. | ||
Each branch uses only few bytes of disk space. | |||
Please see the [http://git-scm.com/docs/git-branch documentation of the <kbd>git branch</kbd> command] for instructions on how to manage and delete branches. | |||
You can also use the <kbd>-b</kbd> option to <kbd>git checkout</kbd> to create a branch and check it out, all in one go. | |||
For example, we could have combined the <kbd>git branch</kbd> and <kbd>git checkout</kbd> commands above as: | |||
<pre> | <pre> | ||
$ | $ git checkout -b my-feature | ||
Switched to a new branch 'my-feature' | |||
</pre> | </pre> | ||
=== Actually making the changes === | |||
: For this section, we'll assume you're in <kbd>qtbase</kbd> on a branch <kbd>my-change</kbd> based on <kbd>dev</kbd>, rather than a branch based on <kbd>master</kbd>. | |||
You can now edit source files, save your edits locally, compile, test and fix any mistakes you've made, in all the usual ways. | |||
Use <kbd>git diff</kbd> to review what you have changed: | |||
<code lang="diff"> | <code lang="diff"> | ||
Line 163: | Line 205: | ||
--- a/src/corelib/tools/qstring.cpp | --- a/src/corelib/tools/qstring.cpp | ||
+++ b/src/corelib/tools/qstring.cpp | +++ b/src/corelib/tools/qstring.cpp | ||
@@ –2855,6 +2855,20 @@ int QString::count(const QRegExp& | @@ –2855,6 +2855,20 @@ int QString::count(const QRegExp& rx) const | ||
Same as size(). | Same as size(). | ||
*/ | */ | ||
+/*! | +/*! | ||
+ | + \since 5.17 | ||
+ | + | ||
+ Returns this string in reverse order. | + Returns this string in reverse order. | ||
Line 177: | Line 219: | ||
+ result.resize(d->size); | + result.resize(d->size); | ||
+ for (int i = 0; i < d->size; ++i) | + for (int i = 0; i < d->size; ++i) | ||
+ | + result[i] = d->data[d->size - 1 - i]; | ||
+ return result; | + return result; | ||
+} | +} | ||
Line 190: | Line 232: | ||
@@ –195,6 +195,8 @@ public: | @@ –195,6 +195,8 @@ public: | ||
int count(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; | int count(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; | ||
int count(const QString & | int count(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const; | ||
+QString reversed() const; | +QString reversed() const; | ||
+ | + | ||
#ifndef QT_NO_REGEXP | #ifndef QT_NO_REGEXP | ||
int indexOf(const QRegExp & | int indexOf(const QRegExp &, int from = 0) const; | ||
int lastIndexOf(const QRegExp & | int lastIndexOf(const QRegExp &, int from = –1) const; | ||
</code> | </code> | ||
Line 203: | Line 245: | ||
<pre> | <pre> | ||
$ git status | $ git status | ||
# On branch | # On branch my-change | ||
# Changed but not updated: | # Changed but not updated: | ||
# (use "git add <file>…" to update what will be committed) | # (use "git add <file>…" to update what will be committed) | ||
Line 214: | Line 256: | ||
</pre> | </pre> | ||
Following the recommendation in the output we mark qstring.cpp and .h as files to be included in the next commit: | Following the recommendation in the output we mark <kbd>qstring.cpp</kbd> and <kbd>qstring.h</kbd> as files to be included in the next commit: | ||
<pre> | <pre> | ||
$ git add src/corelib/tools/qstring.cpp | $ git add src/corelib/tools/qstring.{cpp,h} | ||
$ git status | $ git status | ||
# On branch | # On branch my-change | ||
# Changes to be committed: | # Changes to be committed: | ||
# (use "git reset HEAD <file>…" to unstage) | # (use "git reset HEAD <file>…" to unstage) | ||
Line 233: | Line 275: | ||
<pre> | <pre> | ||
$ git commit -m "Add a new reversed() function to QString" | $ git commit -m "Add a new reversed() function to QString" | ||
[my- | [my-change c8d9c54] Add a new reversed() function to QString | ||
</pre> | </pre> | ||
Normally Git will open a new text editor if you omit the -m parameter. | Normally Git will open a new text editor if you omit the -m parameter. | ||
(If you've [[Setting up Gerrit|set up]] to work with gerrit, you'll have a commit-hook in place, that'll automatically add a <kbd>Change-Id</kbd> footer to your commit message, which will be needed by gerrit.) | |||
Marking files to be included in commits means adding them to Git's staging area. The staging area is a powerful concept, making it easy to work on multiple files | Marking files to be included in commits means adding them to Git's "staging area". | ||
The staging area is a powerful concept, making it easy to work on multiple files simultaneously while still creating small incremental commits. | |||
Use the <tt>git gui</tt> command for a comfortable way to create highly selective commits. | Use the <tt>git gui</tt> command for a comfortable way to create highly selective commits. | ||
Line 252: | Line 296: | ||
</pre> | </pre> | ||
If you have | If you have accidentally marked a file for the next commit, that you don't want to include, you can reset it like this: | ||
<pre> | <pre> | ||
Line 260: | Line 304: | ||
This will exclude the file from the next commit and leave it in your working directory unchanged with your modifications intact. | This will exclude the file from the next commit and leave it in your working directory unchanged with your modifications intact. | ||
After changing a file the git diff command shows the lines you have modified. The difference is calculated from the file in your working directory and the file when it was added to the staging area using git add. | After changing a file the <kbd>git diff</kbd> command shows the lines you have modified. | ||
The difference is calculated from the file in your working directory and the file when it was added to the staging area using <kbd>git add</kbd>. | |||
If you want to show the difference between the file in the staging area and the last commit you have to pass an option to the diff command: | If you want to show the difference between the file in the staging area and the last commit you have to pass an option to the diff command: | ||
<pre> | <pre> | ||
$ git diff | $ git diff --cached | ||
</pre> | </pre> | ||
The diff command optionally takes directories and files as argument, to limit the output. | The diff command optionally takes directories and files as argument, to limit the output. | ||
Files are renamed in Git by renaming them in your working directory using a command/tool of your choice. Once you've renamed a file you | Files are renamed in Git by renaming them in your working directory using a command/tool of your choice. | ||
Once you've renamed a file you need to tell Git: | |||
<pre> | <pre> | ||
Line 286: | Line 332: | ||
One of Git's strengths is that it does not care how exactly you change your files. It is optimized to find out what changed after the fact. For example when copying a file in your source code it is enough to simply run "git add" with the new file. Git automatically finds out where the file was copied from. | One of Git's strengths is that it does not care how exactly you change your files. It is optimized to find out what changed after the fact. For example when copying a file in your source code it is enough to simply run "git add" with the new file. Git automatically finds out where the file was copied from. | ||
To revise the latest commit use <tt>git commit --amend</tt>. | |||
If you want to amend a commit on top of which other commits exist, you need to use <tt>git rebase --interactive</tt>. | |||
== Obtaining updates == | == Obtaining updates == | ||
While developing code in your local clone of the project, the original repository evolves and sees new changes. First we update our mirror of the commits in the original repository using the fetch command: | While developing code in your local clone of the project, the original repository evolves and sees new changes. | ||
First we update our mirror of the commits in the original repository using the fetch command: | |||
<pre> | <pre> | ||
Line 301: | Line 347: | ||
Receiving objects: 100% (1730/1730), 1.13 MiB | 392 KiB/s, done. | Receiving objects: 100% (1730/1730), 1.13 MiB | 392 KiB/s, done. | ||
Resolving deltas: 100% (1455/1455), completed with 892 local objects. | Resolving deltas: 100% (1455/1455), completed with 892 local objects. | ||
From git:// | From git://code.qt.io/qt/qt.git | ||
be7384d..822114e master -> origin/master | be7384d..822114e master -> origin/master | ||
</pre> | </pre> | ||
The output indicates that the "master" branch in the | The output indicates that the "master" branch in the upstream repository has been updated with new commits and these commits are now available in the locally mirrored origin/master branch. | ||
(If you're working in qt5 or one of its sub-modules, "master" won't be the branch you use – you'll have "dev", "5.11" or similar, so use that in place of "master" in the commands below.) | |||
You can inspect the new changes using the log or show commands: | You can inspect the new changes using the log or show commands: | ||
Line 313: | Line 360: | ||
</pre> | </pre> | ||
This log command will include the diffs of the individual commits; if you leave out the <kbd>-p</kbd> argument, you'll just get the summaries. | |||
=== Updating your branch with the downloaded, new changes === | === Updating your branch with the downloaded, new changes === | ||
Line 326: | Line 373: | ||
After making "my-feature" the current branch, git rebase will first re-initialize the branch to be identical to origin/master, which includes the new commits. Then it will apply each of your commits, basing them on top of the newly initialized branch. | After making "my-feature" the current branch, git rebase will first re-initialize the branch to be identical to origin/master, which includes the new commits. Then it will apply each of your commits, basing them on top of the newly initialized branch. | ||
=== | === Getting your feature reviewed === | ||
When you decide that the work in your "my-feature" branch is complete then the next step is to make your changes available for upstream inclusion. | When you decide that the work in your "my-feature" branch is complete then the next step is to make your changes available for upstream inclusion. | ||
This is described in the [[Gerrit Introduction]]. | |||
Once your changes have been integrated, you'll need to update to the new version of the upstream branch ("master" in the above; but probably "dev" or some "5.x" branch). | |||
You can do that by checking it out and doing a <kbd>git pull</kbd>; if you have local changes on this branch, you should <kbd>git pull --rebase</kbd> to keep your local changes separate from the upstream. | |||
Alternatively, you can <kbd>git fetch</kbd> again and rebase your local branches onto suitable upstream branches. | |||
== Conclusion == | == Conclusion == | ||
We hope that this introductions helps you familiarize yourself with the use of Git. The official | We hope that this introductions helps you familiarize yourself with the use of Git. The official | ||
[http://git-scm.com/documentation Git documentation web page] is a very good continuation point. |
Latest revision as of 12:19, 25 July 2018
This document is a simple guide showing the procedures necessary to develop and maintain patches on top of Qt. It is not a replacement for the Git manual.
Git Repositories
This section explains the concept of a Git repository.
$ git clone git://code.qt.io/qt/qt5.git cd qt
This creates a new directory called "qt5" and downloads the source code into it. It also downloads the entire history of all files in all versions, therefore creating an identical copy – called a repository – of what is stored on the server. That is why the process is called cloning. The source of the clone is remembered as the "origin".
Your clone will initially be checked out on some branch, most likely "dev"; you can use git branch -r to find out what branches are available – they'll be listed as origin/dev and similar; the part after origin/ is the name (here, dev) of a branch you can now check out. Pick a suitable branch for the work you want to do and check it out; for example, git checkout dev if you want dev (to which all new features go). Once you've cloned the top-level qt5 super-module and selected a suitable branch, see the README.git file in it for instructions on how to check out all the sub-modules.
You can create new clones simply by copying the directory, for example onto a USB stick. The new directory will be self-contained, too.
Now that you have all the changes inside the repository, you can work 100% offline. An internet connection is necessary only when you need to fetch new source code changes or push upstream.
Inspecting the source code
This section introduces the Git log, show and blame commands to find out the history of the project. You'll usually want to do this for submodules and the files in them; so cd into the submodule you want to work in before you run these commands.
Run the log command to view recent changes:
$ git log
This command launches a pager program allowing you to scroll through the list of committed changes with the cursor and Page Up/Down keys. To return to the shell press the 'q' key.
The log command accepts options, such as -n to limit the number of changes. For example to list the last three changes run:
$ git log -n3
To limit the output of the log command, e.g., to show only changes that affect one or multiple files/directories, you can use the following options:
$ git log src/corelib/kernel $ git log src/gui/kernel/qwindow.cpp $ git log examples/examples.pro examples/widgets/painting/basicdrawing/main.cpp
There are various ways to limit the output of the log command, beyond the ones described here. Refer to git log's documentation for more details. For example, if you're working on a branch based on dev, passing argument dev.. (i.e. put two dots after the base-branch name) will limit to the changes you've made.
Changes in Git are identified with a unique SHA1 checksum. The checksum is on the first line of the git log output. For example (taken from qtbase):
commit 019dd88d2cf63ff065bfd801876b213e8193c60f Author: Friedemann Kleint <Friedemann.Kleint@qt.io> Date: Wed Jul 11 12:59:30 2018 +0200 QStringView: Add compare() member function There was no public API for doing case-insensitive comparisons of QStringView. Task-number: QTBUG-69389 Change-Id: I1b021eefec35e135b97fb87704c8dc137232d83d Reviewed-by: Edward Welbourne <edward.welbourne@qt.io> Reviewed-by: Thiago Macieira <thiago.macieira@intel.com>
You can inspect commits using the git show command with the commit id as argument. The following command shows the entire change above including a diff:
$ git show 019dd88d2cf63ff065bfd801876b213e8193c60f
To see the last commit you made use show without any arguments:
$ git show
To inspect a whole series of commits, pass -p to git log, e.g.
$ git log -p dev..
The git show and log commands allow you to inspect the history of the project or of individual files. Sometimes it is also useful to inspect source code on a line-by-line basis, for example when you would like to find out who introduced a certain snippet of code. Git provides this functionality with the blame command:
$ git blame src/widgets/kernel/qwidget.cpp
The output of this command - shown in a pager - shows each line of the file with a prefix giving the commit id, followed by the author and date, of the last change affecting that line.
Git specializes in tracking the content of files, the name of a file is less important than the source code it contains. Therefore git blame can automatically detect, for example, that a function was moved from one file to another; so it may attribute lines of your file to commits that changed that line before it was moved to the file it's now in.
Making changes
You can change your local copy of Qt if you want to try out something different; usually, you'll want your change integrated upstream. Setting up Gerrit explains how to configure git, and how to clone Qt repositories.
Setting up to make changes
The previous sections explained how to clone the repository and how to find out the history of the project. This section finally shows how to create history, by recording changes as new commits and tracking commits in branches.
The first step is to identify the branch of development on which to base your work. In Git, branches are a very lightweight concept that allows identifying commits by name. Each commit has a reference to its parent commit(s), which forms the history. The git branch command, without any arguments, displays the list of local branches, with a * beside the branch currently checked out:
$ git branch * master
The output shows that we have only one local branch called "master" and the "*" indicates that it is the current branch. The name "master" in Git development usually describes the main line of development.
(This is used by some sub-modules, like qtrepotools, and is the usual form of git repositories. However, most of Qt's sub-modules, along with the qt5 super-module, have other branch names by default. We'll stick with master for this tutorial, but remember you'll usually want to replace it with dev or some other branch name in practice.)
Besides your local branches Git also remembers the branches in the origin repository. The "-r" option shows them, prefixed with "origin":
$ git branch -r origin/4.5 origin/HEAD-> origin/master origin/master
For the purpose of developing a new feature we can create a new branch with the same command:
$ git branch my-feature origin/master
The "my-feature" branch is based on the origin's "master" branch, now visible in the list of branches:
$ git branch * master my-feature
The git checkout command can also change the current branch:
$ git checkout my-feature Switched to branch "my-feature" $ git branch master * my-feature
This will also update the files in your working directory to match the latest commit in the new current branch. New commits will be recorded in "my-feature" instead of the previous "master" branch.
You can have as many local branches as you like, they are very cheap. Each branch uses only few bytes of disk space. Please see the documentation of the git branch command for instructions on how to manage and delete branches.
You can also use the -b option to git checkout to create a branch and check it out, all in one go. For example, we could have combined the git branch and git checkout commands above as:
$ git checkout -b my-feature Switched to a new branch 'my-feature'
Actually making the changes
- For this section, we'll assume you're in qtbase on a branch my-change based on dev, rather than a branch based on master.
You can now edit source files, save your edits locally, compile, test and fix any mistakes you've made, in all the usual ways. Use git diff to review what you have changed:
$ git diff
diff --git a/src/corelib/tools/qstring.cpp b/src/corelib/tools/qstring.cpp
index 375d672..d7345e6 100644
--- a/src/corelib/tools/qstring.cpp
+++ b/src/corelib/tools/qstring.cpp
@@ –2855,6 +2855,20 @@ int QString::count(const QRegExp& rx) const
Same as size().
*/
+/*!
+ \since 5.17
+
+ Returns this string in reverse order.
+ */
+QString QString::reversed() const
+{
+ QString result;
+ result.resize(d->size);
+ for (int i = 0; i < d->size; ++i)
+ result[i] = d->data[d->size - 1 - i];
+ return result;
+}
+
/*!
QString::SectionFlag
diff --git a/src/corelib/tools/qstring.h b/src/corelib/tools/qstring.h
index 1493dce..077bda9 100644
--- a/src/corelib/tools/qstring.h
+++ b/src/corelib/tools/qstring.h
@@ –195,6 +195,8 @@ public:
int count(QChar c, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
int count(const QString &s, Qt::CaseSensitivity cs = Qt::CaseSensitive) const;
+QString reversed() const;
+
#ifndef QT_NO_REGEXP
int indexOf(const QRegExp &, int from = 0) const;
int lastIndexOf(const QRegExp &, int from = –1) const;
The status command gives an overview of what "git commit" would do:
$ git status # On branch my-change # Changed but not updated: # (use "git add <file>…" to update what will be committed) # (use "git checkout -- <file>…" to discard changes in working directory) # # modified: src/corelib/tools/qstring.cpp # modified: src/corelib/tools/qstring.h # no changes added to commit (use "git add" and/or "git commit -a")
Following the recommendation in the output we mark qstring.cpp and qstring.h as files to be included in the next commit:
$ git add src/corelib/tools/qstring.{cpp,h} $ git status # On branch my-change # Changes to be committed: # (use "git reset HEAD <file>…" to unstage) # # modified: src/corelib/tools/qstring.cpp # modified: src/corelib/tools/qstring.h # # Untracked files not listed (use -u option to show untracked files)
And finally we create a new commit:
$ git commit -m "Add a new reversed() function to QString" [my-change c8d9c54] Add a new reversed() function to QString
Normally Git will open a new text editor if you omit the -m parameter. (If you've set up to work with gerrit, you'll have a commit-hook in place, that'll automatically add a Change-Id footer to your commit message, which will be needed by gerrit.)
Marking files to be included in commits means adding them to Git's "staging area". The staging area is a powerful concept, making it easy to work on multiple files simultaneously while still creating small incremental commits.
Use the git gui command for a comfortable way to create highly selective commits.
Common operations and fixing mistakes
This section gives recipes for fixing common mistakes and explains common operations such as reviewing your changes before committing using the diff command.
You can undo changes to a file before it is committed with the checkout command:
$ git checkout HEAD -- src/corelib/tools/qstring.cpp
If you have accidentally marked a file for the next commit, that you don't want to include, you can reset it like this:
$ git reset HEAD -- src/corelib/tools/qstring.cpp
This will exclude the file from the next commit and leave it in your working directory unchanged with your modifications intact.
After changing a file the git diff command shows the lines you have modified. The difference is calculated from the file in your working directory and the file when it was added to the staging area using git add.
If you want to show the difference between the file in the staging area and the last commit you have to pass an option to the diff command:
$ git diff --cached
The diff command optionally takes directories and files as argument, to limit the output.
Files are renamed in Git by renaming them in your working directory using a command/tool of your choice. Once you've renamed a file you need to tell Git:
[ rename oldfile.cpp to newfile.cpp using a graphical file manager ] $ git rm oldfile.cpp $ git add newfile.cpp
Alternatively you can use the convenience mv command:
$ git mv oldfile.cpp newfile.cpp
One of Git's strengths is that it does not care how exactly you change your files. It is optimized to find out what changed after the fact. For example when copying a file in your source code it is enough to simply run "git add" with the new file. Git automatically finds out where the file was copied from.
To revise the latest commit use git commit --amend. If you want to amend a commit on top of which other commits exist, you need to use git rebase --interactive.
Obtaining updates
While developing code in your local clone of the project, the original repository evolves and sees new changes. First we update our mirror of the commits in the original repository using the fetch command:
$ git fetch remote: Counting objects: 3013, done. remote: Compressing objects: 100% (395/395), done. remote: Total 1730 (delta 1455), reused 1582 (delta 1332) Receiving objects: 100% (1730/1730), 1.13 MiB | 392 KiB/s, done. Resolving deltas: 100% (1455/1455), completed with 892 local objects. From git://code.qt.io/qt/qt.git be7384d..822114e master -> origin/master
The output indicates that the "master" branch in the upstream repository has been updated with new commits and these commits are now available in the locally mirrored origin/master branch. (If you're working in qt5 or one of its sub-modules, "master" won't be the branch you use – you'll have "dev", "5.11" or similar, so use that in place of "master" in the commands below.)
You can inspect the new changes using the log or show commands:
$ git log -p origin/master
This log command will include the diffs of the individual commits; if you leave out the -p argument, you'll just get the summaries.
Updating your branch with the downloaded, new changes
To combine the new changes with our own local commits we use a technique called rebasing:
$ git checkout my-feature $ git rebase origin/master
After making "my-feature" the current branch, git rebase will first re-initialize the branch to be identical to origin/master, which includes the new commits. Then it will apply each of your commits, basing them on top of the newly initialized branch.
Getting your feature reviewed
When you decide that the work in your "my-feature" branch is complete then the next step is to make your changes available for upstream inclusion. This is described in the Gerrit Introduction.
Once your changes have been integrated, you'll need to update to the new version of the upstream branch ("master" in the above; but probably "dev" or some "5.x" branch). You can do that by checking it out and doing a git pull; if you have local changes on this branch, you should git pull --rebase to keep your local changes separate from the upstream. Alternatively, you can git fetch again and rebase your local branches onto suitable upstream branches.
Conclusion
We hope that this introductions helps you familiarize yourself with the use of Git. The official Git documentation web page is a very good continuation point.