Changes between Version 49 and Version 50 of WorkingWithGit


Ignore:
Timestamp:
Aug 26, 2016, 6:49:38 PM (8 years ago)
Author:
neverpanic (Clemens Lang)
Comment:

Reorganize and consolidate common sections

Legend:

Unmodified
Added
Removed
Modified
  • WorkingWithGit

    v49 v50  
    66
    77== Initial setup == #Initialsetup
    8 
    9 {{{
    10 #!comment
    11 TODO: Move this section to a separate wiki page.
    12 }}}
    13 
    148Git commits contain your name and email address. You should set them in your git configuration using the following commands:
    159{{{
     
    1913If you work on multiple Git projects and do not want to modify your email address for those, these commands can also be run without `--global` in a clone of MacPorts' repositories to only change the option for these repositories. If you are not a MacPorts committer, use any email address.
    2014
    21 '''T.B.D.:''' MacPorts ports contributors should be encouraged to fork the original MacPorts {{{git}}} repository and introduce changes only in their forked repos. Contributions can then be "filed" to the original repo using GitHub's pull requests (PR). These PRs allow for user-friendly reviewing, commenting and in the future possibly also immediate issuing of CI builds.
    22 
    23 
    24 == Common `git` tasks while working with ports ==
    25 
    26 Then
    27 {{{
    28 svn checkout https://svn.macports.org/repository/macports/trunk/dports
    29 }}}
    30 becomes
    31 {{{
    32 git clone git@github.com:macports/ports.git
    33 }}}
    34 When you clone you will get the entire history of the ports tree, with the latest version being checked out in the filesystem.
    35 After you make a change, you can run {{{ git status }}}
    36 and get something like this.
    37 {{{
    38 On branch master
    39 Your branch is up-to-date with 'origin/master'.
    40 Changes not staged for commit:
    41   (use "git add <file>..." to update what will be committed)
    42   (use "git checkout -- <file>..." to discard changes in working directory)
    43 
    44         modified:   aqua/iTerm2/Portfile
    45 
    46 no changes added to commit (use "git add" and/or "git commit -a")
    47 }}}
    48 What this tells me, is that I've changed a Portfile, but not done anything.
    49 After that, you can add the files that you want to add to your commit using {{{git add aqua/iTerm2/Portfile}}}.
    50 Now, {{{git status}}} will look like:
    51 {{{
    52 On branch master
    53 Your branch is up-to-date with 'origin/master'.
    54 Changes to be committed:
    55   (use "git reset HEAD <file>..." to unstage)
    56 
    57         modified:   aqua/iTerm2/Portfile
    58 }}}
    59 Then run {{{git commit}}} and everything is set. On your machine. To push to github you then have to run {{{git push}}}.
    60 
    61 
    62 == Common `git` tasks while working with MacPorts base ==
    63 
    64 === Checking out a working copy === #clone
    65 The source code of MacPorts itself is no longer managed in the same repository as all ports. Contrary to Subversion, checking out a sub-directory of a repository is not possible with Git. In order to avoid that all port maintainers have to clone the complete history of MacPorts base as well, the Subversion repository has been split into multiple separate repositories. MacPorts base is now available using
    66 {{{
    67 git clone git@github.com:macports/base.git # or
    68 git clone https://github.com/macports/base.git # if SSH does not work on your network
    69 }}}
    70 
    71 See the [#reposplit section on repository splitting during the export] to get an overview of where a path in the old Subversion history is now available in Git.
     15
     16
     17
     18
     19== Common `git` tasks & notes about MacPorts' Subversion export ==
     20
     21
     22=== Getting a working copy ===
     23To start working with git, you need a copy of the sources. Follow the sections for [#cloneports getting the ports tree] or [#clone MacPorts base], depending on where you want to make changes, then continue with the next section.
     24
    7225
    7326=== Committing changes in your working copy === #commit
     
    10255Note that the push will fail if the remote repository has new changes. Contrary to Subversion, it does not matter whether your changes conflict with the remote ones. If this happens, you must update your local working copy as described in the [#updating section on fetch the latest changes] and re-try the push.
    10356
    104 === Merge a single change from master into a release branch === #cherrypick
    105 The equivalent to Subversion's `svn merge -c <revision> .` is `git cherry-pick`. Use `git cherry-pick` to apply a single change from master to a release branch. To do this, look up the commit ID of the commit you want to pick:
    106 {{{
    107 git log
    108 # copy the commit ID
    109 }}}
    110 Switch to the target branch of the cherry pick:
    111 {{{
    112 git checkout release_2_3
    113 }}}
    114 Cherry-pick the commit. It is good practice to pass `-x` to `git cherry-pick`, which will automatically add a "Cherry picked from commit <commmitID>" line to the commit message of your cherry pick. You will have the option to modify the commit message, e.g. to describe why the backport was necessary.
    115 {{{
    116 git cherry-pick -x <commitID>
    117 }}}
    118 Finally, push the new commit using
    119 {{{
    120 git push origin <branchname>
    121 }}}
    122 
    123 == Common `git` tasks & notes about MacPorts' Subversion export ==
    124 === Fetching the latest changes === #updating
    125 Git's equivalent to `svn update` is a little more complicated due to Git's distributed nature. Most of the complexity is not visible if you do not have commits in your working copy that have not been pushed yet. If both the local and the remote repository have changes (git calls them "diverged"), you will run into one of Git's core principles: Every commit has (at least) one parent commit, i.e. the commit history forms a directed acyclic graph.
    126 
    127 ==== Background knowledge ====
    128 
    129 A picture is worth a thousand words:
    130 {{{
    131  A --- B --- C ---- R1 ---- R2 ---- R3  <= origin/master
    132               \
    133                +--- L1 ---- L2          <= master
    134 }}}
    135 A, B and C are commits that are both in your local and in the remote repository. R1-3 are commits that have been pushed into the remote repository "origin"'s master branch while you were working. L1 and L2 are commits you prepared locally on your master branch. Git offers two different ways to bring R1-3 into your local branch:
    136 
    137 ===== Merging =====
    138 A merge commit, created by `git merge`, is a commit that has multiple parents. If no conflict occurs, merge commits do not usually have a diff attached (i.e. they do not modify files). On conflict, merge commits contain the diff that resolves the conflict. In pictures:
    139 {{{
    140  A --- B --- C ---- R1 ---- R2 ---- R3   <= origin/master
    141               \                      \
    142                +--- L1 ---- L2 ------ M  <= master
    143 }}}
    144 The new commit M is the merge commit and can be pushed back to origin. This preserves the information that work was done in parallel, but unfortunately tends to mess up the history graph. See the [raw-attachment:commit-history-with-excessive-merging.png attached screenshot] of a commit history that always merges. To avoid this, you can instead rebase your changes.
    145 
    146 ===== Rebasing =====
    147 Rebasing commits rewrites their parent commit IDs and avoids the need for a merge commit. Running `git rebase origin/master` will take all commits in your local working copy that are not yet pushed and attach them after the end of `origin/master`, which yields this picture:
    148 {{{
    149  A --- B --- C ---- R1 ---- R2 ---- R3   <= origin/master
    150                                       \
    151                                        L1' ---- L2'  <= master
    152 
    153 }}}
    154 Note that L1 and L2 have been modified by this operation; their commit IDs changed because of that. This new state can be pushed back to origin without the need for a merge commit, and the history graph will stay linear. '''We recommend that all developers rebase their changes rather than merge when conflicts occur during pushing.'''
    155 
    156 ==== Putting the background knowledge into production ====
    157 First, get all new commits from the remote repository using `git fetch <remote-name>`, where `<remote-name>` identifies the repository from which you want to fetch and defaults to "origin":
    158 {{{
    159 git fetch
    160 }}}
    161 Then, rebase your local changes (if any) on top of any new changes in the remote repository and fix any conflicts that occur:
    162 {{{
    163 git rebase origin/master
    164 }}}
    165 
    166 Because these two operations are very common, Git offers a shorthand for them:
    167 {{{
    168 git pull --rebase
    169 }}}
    170 
    171 '''Note:''' `git rebase` requires that you do not have uncommitted modifications in your working copy. If you have modifications, you can temporarily save them using `git stash` and restore them after the rebase using `git stash pop`.
    172 
    173 '''Warning:''' `git pull` without the `--rebase` flag is a shorthand for `git fetch && git merge origin/master`, which will automatically create a merge commit if it thinks that's necessary.
    174 
    175 If you do not want to remember passing `--rebase` to `git pull` every time you run it, you can set a couple of [https://git-scm.com/docs/git-config git-config(1)] options to make it the default:
    176 
    177  - Setting `pull.rebase` to `true` will change the default to always rebase when calling `git pull`. Note that this will also flatten any local merge commits you might have committed on purpose with `git merge`, which might be undesirable when merging development branches for MacPorts base. Consider using the `preserve` setting, which avoids this.
    178  - Rebasing can be enabled on a per-branch basis using the `branch.<name>.rebase` setting, which accepts the same values as `pull.rebase`.
    179  - You can make `branch.<name>.rebase true` the default for all branches that you clone by setting `branch.autoSetupRebase` to `always`. This allows you to change the setting back to a different value for specific branches but still keep the default to rebase. Note that this setting will not affect branches that you have already created.
    18057
    18158=== Commit messages === #commitmessages
     
    19269If you don't want to remember these rules, you can configure your git client to load a template whenever it prompts you for a commit message by setting the `commit.template` [https://git-scm.com/docs/git-config git-config(1)] option. The KDE developers [https://quickgit.kde.org/?p=macports-kde.git&a=blob&h=14f952f776b9f54263671cc2aba5886c6ebee75b&f=contrib%2Fgit-setup%2F.git-commit-template&o=plain have a nice example].
    19370
     71
     72=== Fetching the latest changes === #updating
     73Git's equivalent to `svn update` is a little more complicated due to Git's distributed nature. Most of the complexity is not visible if you do not have commits in your working copy that have not been pushed yet. If both the local and the remote repository have changes (git calls them "diverged"), you will run into one of Git's core principles: Every commit has (at least) one parent commit, i.e. the commit history forms a directed acyclic graph.
     74
     75==== Background knowledge ====
     76
     77A picture is worth a thousand words:
     78{{{
     79 A --- B --- C ---- R1 ---- R2 ---- R3  <= origin/master
     80              \
     81               +--- L1 ---- L2          <= master
     82}}}
     83A, B and C are commits that are both in your local and in the remote repository. R1-3 are commits that have been pushed into the remote repository "origin"'s master branch while you were working. L1 and L2 are commits you prepared locally on your master branch. Git offers two different ways to bring R1-3 into your local branch:
     84
     85===== Merging =====
     86A merge commit, created by `git merge`, is a commit that has multiple parents. If no conflict occurs, merge commits do not usually have a diff attached (i.e. they do not modify files). On conflict, merge commits contain the diff that resolves the conflict. In pictures:
     87{{{
     88 A --- B --- C ---- R1 ---- R2 ---- R3   <= origin/master
     89              \                      \
     90               +--- L1 ---- L2 ------ M  <= master
     91}}}
     92The new commit M is the merge commit and can be pushed back to origin. This preserves the information that work was done in parallel, but unfortunately tends to mess up the history graph. See the [raw-attachment:commit-history-with-excessive-merging.png attached screenshot] of a commit history that always merges. To avoid this, you can instead rebase your changes.
     93
     94===== Rebasing =====
     95Rebasing commits rewrites their parent commit IDs and avoids the need for a merge commit. Running `git rebase origin/master` will take all commits in your local working copy that are not yet pushed and attach them after the end of `origin/master`, which yields this picture:
     96{{{
     97 A --- B --- C ---- R1 ---- R2 ---- R3   <= origin/master
     98                                      \
     99                                       L1' ---- L2'  <= master
     100
     101}}}
     102Note that L1 and L2 have been modified by this operation; their commit IDs changed because of that. This new state can be pushed back to origin without the need for a merge commit, and the history graph will stay linear. '''We recommend that all developers rebase their changes rather than merge when conflicts occur during pushing.'''
     103
     104==== Putting the background knowledge into production ====
     105First, get all new commits from the remote repository using `git fetch <remote-name>`, where `<remote-name>` identifies the repository from which you want to fetch and defaults to "origin":
     106{{{
     107git fetch
     108}}}
     109Then, rebase your local changes (if any) on top of any new changes in the remote repository and fix any conflicts that occur:
     110{{{
     111git rebase origin/master
     112}}}
     113
     114Because these two operations are very common, Git offers a shorthand for them:
     115{{{
     116git pull --rebase
     117}}}
     118
     119'''Note:''' `git rebase` requires that you do not have uncommitted modifications in your working copy. If you have modifications, you can temporarily save them using `git stash` and restore them after the rebase using `git stash pop`.
     120
     121'''Warning:''' `git pull` without the `--rebase` flag is a shorthand for `git fetch && git merge origin/master`, which will automatically create a merge commit if it thinks that's necessary.
     122
     123If you do not want to remember passing `--rebase` to `git pull` every time you run it, you can set a couple of [https://git-scm.com/docs/git-config git-config(1)] options to make it the default:
     124
     125 - Setting `pull.rebase` to `true` will change the default to always rebase when calling `git pull`. Note that this will also flatten any local merge commits you might have committed on purpose with `git merge`, which might be undesirable when merging development branches for MacPorts base. Consider using the `preserve` setting, which avoids this.
     126 - Rebasing can be enabled on a per-branch basis using the `branch.<name>.rebase` setting, which accepts the same values as `pull.rebase`.
     127 - You can make `branch.<name>.rebase true` the default for all branches that you clone by setting `branch.autoSetupRebase` to `always`. This allows you to change the setting back to a different value for specific branches but still keep the default to rebase. Note that this setting will not affect branches that you have already created.
     128
     129
    194130=== Reverting changes === #revert
    195131Subversion has two methods for reverting changes: `svn revert`, which drops uncommitted local modifications and restores the committed state and `svn merge -c -12345` to undo committed changes.
     
    200136 - To undo a change that has already been committed and pushed, use `git revert <commitID>`. This will create a new commit that applies the inverse diff. Note that you still have to push this commit to publish it.
    201137 - To throw away all changes that you have locally committed but not yet pushed, use `git reset --hard origin/master`. '''You will loose all your uncommitted and committed modifications.''' If that is not what you want, Git provides a variety of tools that allow you to change commits that you have not pushed yet (and theoretically also commits that have already been pushed, which will prevent you from pushing any changes again). Since this is an advanced topic it will not be covered here. As a pointer for further research, look for `git commit --amend` to change the topmost commit and `git rebase --interactive`, the so-called "interactive rebase", to change older commits.
     138
    202139
    203140=== Repository split === #reposplit
     
    229166
    230167
     168
     169
     170
     171== Common `git` tasks while working with ports ==
     172
     173
     174=== Checking out a working copy of the ports tree === #cloneports
     175To get a working copy of the MacPorts ports tree to start changing ports, clone of copy of the repository:
     176{{{
     177git clone git@github.com:macports/ports.git # or
     178git clone https://github.com/macports/ports.git # if SSH does not work on your network
     179}}}
     180
     181This will give you the entire history of the ports tree, with the latest version being checked out in the filesystem.
     182
     183'''Note:''' If you intend to submit a pull request on GitHub to get your changes included in MacPorts, you may want to create a fork of the repository first. To do that, go to https://github.com/macports/ports/ and click the fork button at the top right. Then, run the command above, but use `<yourusername>/ports.git` instead of `macports/ports.git`.
     184
     185See the [#commit section on committing changes] to find out how to get your changes into the repository.
     186
     187
     188
     189
     190
     191== Common `git` tasks while working with MacPorts base ==
     192
     193
     194=== Checking out a working copy of MacPorts base === #clone
     195The source code of MacPorts itself is no longer managed in the same repository as all ports. Contrary to Subversion, checking out a sub-directory of a repository is not possible with Git. In order to avoid that all port maintainers have to clone the complete history of MacPorts base as well, the Subversion repository has been split into multiple separate repositories. MacPorts base is now available using
     196{{{
     197git clone git@github.com:macports/base.git # or
     198git clone https://github.com/macports/base.git # if SSH does not work on your network
     199}}}
     200
     201See the [#reposplit section on repository splitting during the export] to get an overview of where a path in the old Subversion history is now available in Git.
     202
     203
     204=== Merge a single change from master into a release branch === #cherrypick
     205The equivalent to Subversion's `svn merge -c <revision> .` is `git cherry-pick`. Use `git cherry-pick` to apply a single change from master to a release branch. To do this, look up the commit ID of the commit you want to pick:
     206{{{
     207git log
     208# copy the commit ID
     209}}}
     210Switch to the target branch of the cherry pick:
     211{{{
     212git checkout release_2_3
     213}}}
     214Cherry-pick the commit. It is good practice to pass `-x` to `git cherry-pick`, which will automatically add a "Cherry picked from commit <commmitID>" line to the commit message of your cherry pick. You will have the option to modify the commit message, e.g. to describe why the backport was necessary.
     215{{{
     216git cherry-pick -x <commitID>
     217}}}
     218Finally, push the new commit using
     219{{{
     220git push origin <branchname>
     221}}}
     222
     223
     224
     225
     226
    231227== Tools == #tools
    232228
     
    234230- [http://gitx.frim.nl GitX] is a graphical repository browser designed for macOS. Unfortunately, our `GitX` port is [[ticket:42957|currently nonfunctional]].
    235231- [http://jonas.nitro.dk/tig Tig] is an ncurses-based interface, available from the `tig` port.
     232
     233
     234
    236235
    237236