Git notes (23) contributions from different roles

Git notes (23) contributions from different roles

1. Private small team

The simplest configuration you may encounter is a private (closed source) project with one or two developers
They and other developers have push permission of the warehouse

In this environment, you can adopt a workflow similar to that used when using Subversion or other centralized systems
You can still get advanced functions such as offline submission, easily creating new branches and merging branches
But the workflow can be very simple, with the main differences:
Merge occurs on the client side, not on the server side at commit time

The first developer, Jove, cloned the repository, made changes, and then submitted locally

# Jove's Machine
$ git clone Jove@githost:simplegit.git
Initialized empty Git repository in /home/Jove/simplegit/.git/
$ cd simplegit/
$ vim lib/simplegit.rb
$ git commit -am 'removed invalid default value'
[master 738ee87] removed invalid default value
 1 files changed, 1 insertions(+), 1 deletions(-)

The second developer, Jasek, did the same thing, cloned the repository and submitted a change:

#  Jasek's Machine
$ git clone Jasek@githost:simplegit.git
Initialized empty Git repository in /home/Jasek/simplegit/.git/
$ cd simplegit/
$ vim TODO
$ git commit -am 'add reset task'
[master fbff5bc] add reset task
 1 files changed, 1 insertions(+), 0 deletions(-)

Now, Jasek pushes his work to the server:

# Jasek's Machine
$ git push origin master
To Jasek@githost:simplegit.git
   1edee6b..fbff5bc  master -> master

Jove also tried to push his changes:

# Jove's Machine
$ git push origin master
To Jove@githost:simplegit.git
 ! [rejected]        master -> master (non-fast forward)
error: failed to push some refs to 'Jove@githost:simplegit.git'

Jove push is not allowed here because Jasek already pushed at the same time
Although Subversion will automatically merge the different files edited once on the server
But Git requires you to merge and submit locally
Jove has to grab Jasek's changes and merge them to be allowed to push

$ git fetch origin
From Jove@githost:simplegit
 + 049d078...fbff5bc master     -> origin/master

At this time, Jove's local warehouse looks like this:

Jove (yellow) has a reference to a change pushed by Jasek (green)
But he has to incorporate them into his work before he can be allowed to push

$ git merge origin/master
Merge made by recursive.
 TODO |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

The merger went well - Jove's submission history now looks like this:

Now, Jove can test the code to make sure it still works
Then he can push the merged new work to the server:

$ git push origin master
To jove@githost:simplegit.git
   fbff5bc..72bbc59  master -> master

Finally, Jove's submission history looks like this:

During this time, Jasek worked on a feature branch
Created a feature branch called issue54 and committed three times on that branch
At this time, Jove's changes have not been captured, so the submission history looks like this:

Jasek wants to synchronize with Jove, so he grabs:

# Jasek's Machine
$ git fetch origin
From Jasek@githost:simplegit
   fbff5bc..72bbc59  master     -> origin/master

That would pull jobs that Jove pushed at the same time, and Jasek's history now looks like this:

Jasek wants to know what has to be merged into his work to push
Run git log to find out:

$ git log --no-merges issue54..origin/master
commit 738ee872852dfaa9d6634e0dea7a324040193016
Author: Jove <>
Date:   Fri May 29 16:01:27 2009 -0700

   removed invalid default value

The issue54..origin/master syntax is a log filter
It requires Git to display only a list of all commits that are in the origin/master branch but not in the issue 54 branch

At present, you can see from the output that there is a commit generated by Jove but not merged by Jasek
If he merges the origin/master, that is to say, the single commit of his local work will be modified

Now, Jasek can merge his features into his master branch
Merge Jove's work (origin/master) into his master branch
Then push it back to the server again

First, in order to integrate all these works, he switches back to his master branch.

$ git checkout master
Switched to branch 'master'
Your branch is behind 'origin/master' by 2 commits, and can be fast-forwarded.

He can merge both origin/master and issue54 first -- they are all upstream, so the order doesn't matter
No matter what order he chooses, the final result is exactly the same
It's just that there's a slight difference in history

Join him and choose to merge into issue54 first:

$ git merge issue54
Updating fbff5bc..4af4298
Fast forward
 README           |    1 +
 lib/simplegit.rb |    6 +++++-
 2 files changed, 6 insertions(+), 1 deletions(-)

No problem; as you can see, it's a simple fast forward
Now, Jasek merges into Jove's work (origin/master):

$ git merge origin/master
Auto-merging lib/simplegit.rb
Merge made by recursive.
 lib/simplegit.rb |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

Every file is merged cleanly, and Jasek's history looks like this:

Now the origin/master can be reached from the master branch of Jasek
So he should be able to successfully push (assuming that Jove did not push again at the same time):

$ git push origin master
To jasek@githost:simplegit.git
   72bbc59..8059c15  master -> master

Each developer submitted several times and successfully merged the work of others

This is the simplest workflow:

  • Usually work in a feature branch for a while
  • Merge back to its master branch when it's ready to consolidate
  • When you want to share work, merge it back to your own master branch
  • If there is any change, then grab and merge the origin/master so that the current master branch can point to the origin/master
  • Finally pushed to the master branch on the server

The order is usually like this:

2. Private management team

Teams collaborate based on features, and their contributions will be integrated by others
Bold style
Suppose that Jove and Jasek work on one feature, while Jasek and Wallace work on the second
The company uses an integration manager workflow:
The work of the independent team can only be integrated by specific engineers, and the master branch of the main warehouse can only be updated by those engineers
In this case, all work is done on the team based branch and later pulled together by the integrators

Because Jasek works on two features and works in parallel with two different developers
Assuming that he has cloned the warehouse, he first decides to work on feature a
He created a new branch for that feature and did some work there:

# Jasek's Machine
$ git checkout -b featureA
Switched to a new branch 'featureA'
$ vim lib/simplegit.rb
$ git commit -am 'add limit to log function'
[featureA 3300904] add limit to log function
 1 files changed, 1 insertions(+), 1 deletions(-)

At this time, the work needs to be shared with Jove, so the submission of feature a branch is pushed to the server

Jasek does not have push permission for the master branch (only the integrator does), so in order to work with Jove, another branch must be pushed

$ git push -u origin featureA
To Jasek@githost:simplegit.git
 * [new branch]      featureA -> featureA

Jasek emailed Jove that he had pushed some work to the feature a branch, and now we can have a look
As he waited for Jove's feedback, Jasek decided to work with Wallace on featureB
To get started, the server based master branch starts a new branch

# Jasek's Machine
$ git fetch origin
$ git checkout -b featureB origin/master
Switched to a new branch 'featureB'

Now, Jasek has created several commits on the featureB branch:

$ vim lib/simplegit.rb
$ git commit -am 'made the ls-tree function recursive'
[featureB e5b0fdc] made the ls-tree function recursive
 1 files changed, 1 insertions(+), 1 deletions(-)
$ vim lib/simplegit.rb
$ git commit -am 'add ls-files'
[featureB 8512791] add ls-files
 1 files changed, 5 insertions(+), 0 deletions(-)

Now, Jasek's warehouse looks like this:

Ready to push
But an email from Wallace tells us that some initial work has been pushed to the featureBee on the server
So Jasek needs to merge those changes with his own before he can push them to the server
Now you can use git fetch to capture Wallace's changes:

$ git fetch origin
From Jasek@githost:simplegit
 * [new branch]      featureBee -> origin/featureBee

Jasek can now merge it into his work through git merge:

$ git merge origin/featureBee
Auto-merging lib/simplegit.rb
Merge made by recursive.
 lib/simplegit.rb |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

There's a problem. You need to push the merged work on the featureB branch to the featureBee branch on the server
Here you can do this by specifying the local branch plus a colon (:) plus a remote branch to the git push command:

$ git push -u origin featureB:featureBee
To Jasek@githost:simplegit.git
   fba9af8..cd685d1  featureB -> featureBee

This is called a reference specification

Then Jove emailed Jasek that he had pushed some changes to the feature a branch and asked him to verify them
Jasek quickly runs a git fetch to pull down the changes:

$ git fetch origin
From Jasek@githost:simplegit
   3300904..aad881d  featureA   -> origin/featureA

Then, you can see what has changed through git log:

$ git log featureA..origin/featureA
commit aad881d154acdaeb2b6b18ea0e827ed8a6d671e6
Author: Jove <>
Date:   Fri May 29 19:57:33 2009 -0700

    changed log output to 30 from 25

Finally, merge Jove's work into his feature a branch:

$ git checkout featureA
Switched to branch 'featureA'
$ git merge origin/featureA
Updating 3300904..aad881d
Fast forward
 lib/simplegit.rb |   10 +++++++++-
1 files changed, 9 insertions(+), 1 deletions(-)

Jasek wants to tweak something slightly, so commit again and push it back to the server:

$ git commit -am 'small tweak'
[featureA 774b3ed] small tweak
 1 files changed, 1 insertions(+), 1 deletions(-)
$ git push
To Jasek@githost:simplegit.git
   3300904..774b3ed  featureA -> featureA

Jasek's submission history now looks like this:

Jasek, Wallace, and Jove inform integrators that the featureA and featureBee branches on the server are ready to be integrated into the main line
After the integrator merges these branches to the main line, a new merge submission will be taken down in one grab
History looks like this:

Many teams switch to Git because of the ability to allow multiple teams to work in parallel and then merge different jobs
Smaller sub groups in the team can collaborate through remote branches
Without affecting or hindering the ability of the whole team
The workflow sequence you see here is similar to this:

3. Derived public projects

It's a little different to contribute to open projects
Because you do not have permission to directly update the branches of the project, you must use other methods to give the work to the maintainer

Using derivation to contribute on Git hosting that supports simple derivation is described here
Many hosting sites support this function, including GitHub, BitBucket, Google Code, etc

First, you may want to clone the main warehouse
Create a feature branch for the patch or patch sequence you plan to contribute and work there
The sequence looks like this:

$ git clone (url)
$ cd project
$ git checkout -b featureA
# (work)
$ git commit
# (work)
$ git commit

You may want to use rebase-i to compress the work into a single commit
Or reschedule the work in the submission to make the patch easier to be reviewed by the maintainer

Prepare to contribute branch work back to maintainer when it is completed
Go to the original project and click the "Fork" button to create a writable project derived warehouse

Then you need to add the new warehouse URL as the second remote warehouse. In this case, it is called myfork:

$ git remote add myfork (url)

And then you need to push the work up there

$ git push -u myfork featureA

It is easier to push the working feature to branch to the warehouse than to merge it into the main branch and push it up
The reason is that if the work is not accepted or picked, you do not have to back off your master branch
If the maintainer merges, bases, or selects your work
Anyway, you'll eventually get your job back by pulling their warehouse

When the work has been pushed to a derivation, the maintainer needs to be notified
This is often referred to as a pull request, which can be generated from a website

GitHub has its own Pull Request mechanism

You can also run the GIT request pull command and manually email the output to the maintainer of the project

The request pull command accepts the underlying branches pulled in by the feature branches and the Git warehouse URL they pull in
Output a summary of all changes pulled in by the request

For example, Jasek wants to send a pull request to Jove
He has committed twice on the branch he just pushed. You can run this:

$ git request-pull origin/master myfork
The following changes since commit 1edee6b1d61823a2de3b09c160d7080b8d1b3a40:
  Jove Smith (1):
        added a new function

are available in the git repository at:

  git://githost/simplegit.git featureA

Jasek (2):
      add limit to log function
      change log output to 30 from 25

 lib/simplegit.rb |   10 +++++++++-
 1 files changed, 9 insertions(+), 1 deletions(-)

This output can be sent to the maintainer
It tells them where the work starts, where the induction is committed, and where to pull it in

On a project where you're not a maintainer
It is usually convenient to have a master branch that always tracks origin/master
Working on feature branches is because you can easily discard them if they are rejected

If the main warehouse moves at the same time, then your submission can no longer be applied cleanly
Making the work topic independent of the feature branch also makes it easier for you to rebase your work

For example, to provide a second feature to work on a project, do not continue to work on the feature branch that was just pushed
Restart from the master branch of the master warehouse:

$ git checkout -b featureB origin/master
# (work)
$ git commit
$ git push myfork featureB
# (email maintainer)
$ git fetch origin

Now, each feature is stored in a repository, similar to the patch queue
You can override, base, and modify properties without interfering or relying on each other, like this:

Suppose the project maintainer has pulled a string of other patches
Then try to pull your first branch, but not merge cleanly

In this case, you can try to change the base branch to the top of the origin/master to resolve the conflict for the maintainer
Then resubmit the changes:

$ git checkout featureA
$ git rebase origin/master
$ git push -f myfork featureA

This will rewrite your history. Now it looks like the submission history after featureA works

The - f option must be specified for the push command because the branch has been rebased
In this way, the submitted feature a branch on the server that is not its descendant can be replaced
An alternative is to push the new work to a different branch on the server (perhaps called featureAv2)

Let's look at a more likely scenario:
Maintainers see the work on your second branch, featureB, and love the concept
But I want you to modify the details of the implementation
You can also use this opportunity to base your work on the current master branch of the project
You start a new branch from the current origin/master branch
Compress the changes to featureB there, resolve any conflicts, change the implementation, and push it as a new branch

$ git checkout -b featureBv2 origin/master
$ git merge --squash featureB
# (change implementation)
$ git commit
$ git push myfork featureBv2

--The square option takes all the work on the merged branch and compresses it into a changeset
Make the warehouse into a state where a real merge occurs without actually generating a merge submission

This means that your future commit will have only one parent commit and allow you to introduce all changes to another branch
Then make more changes before recording a new submission

Also -- the no commit option can be used to delay the generation of merge commits during the default merge process

Now you can send a message to the maintainer that you have made the required changes
Then they can find the changes on the feature BV2 branch

4. Open items by email

Many projects have established a process for accepting patches
The specific rules for each project need to be examined because there are differences between them
Because there are several long-standing, large projects that will receive patches through a developer's mailing list

Now I'll show you an example
The workflow is similar to the previous use case: Create Feature branches for each patch sequence of work
The difference is how to submit them to the project

Generate e-mail versions of each submission sequence and mail them to the developer mailing list
Instead of deriving the project and pushing it to your own writable version

$ git checkout -b topicA
# (work)
$ git commit
# (work)
$ git commit

Now there are two submissions to send to the mailing list
Using git format patch to generate a file in mbox format that can be mailed to a list
It transforms each submission into an email, with the first line of the submission information as the subject, and the remaining information and the patch introduced by the submission as the body

One advantage is that the submission of an email application generated correctly retains all the submitted information

$ git format-patch -M origin/master

Print out the name of the patch file it created, - M switch tells Git to find and rename

The file ends up looking like this:

$ cat 0001-add-limit-to-log-function.patch
From 330090432754092d704da8e76ca5c05c198e71a8 Mon Sep 17 00:00:00 2001
From: Jessica <>
Date: Sun, 6 Apr 2008 10:17:23 -0700
Subject: [PATCH 1/2] add limit to log function

Limit log functionality to the first 20

 lib/simplegit.rb |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/lib/simplegit.rb b/lib/simplegit.rb
index 76f47bc..f9815f1 100644
--- a/lib/simplegit.rb
+++ b/lib/simplegit.rb
@@ -14,7 +14,7 @@ class SimpleGit

   def log(treeish = 'master')
-    command("git log #{treeish}")
+    command("git log -n 20 #{treeish}")

   def ls_tree(treeish = 'master')

You can also edit these patch files to add more information to the mailing list that you don't want to show in the submission information
If you add text between the -- line and the beginning of the patch (diff --git line), the developer can read it
But it will be excluded when applying the patch

To mail it to the mailing list
You can paste the file into an email client or send it through a command line program
But pasting text often causes formatting problems

Fortunately, Git provides a tool to help you send properly formatted patches through IMAP
Now I'll show you how to send a patch via Gmail

It can be mentioned before Git source code Medium Documentation/SubmittingPatches To learn the detailed instructions of a series of mail programs

First, you need to set the imap block in the ~ /. gitconfig file
You can set each value individually through a series of git config commands, or add them manually
Anyway, the final configuration file should look like this:

  folder = "[Gmail]/Drafts"
  host = imaps://
  user =
  pass = p4ssw0rd
  port = 993
  sslverify = false

If the imap server does not use SSL, the last two lines are unnecessary, and the host will be imap: / /, not imaps://
When those settings are complete, you can use git IMAP send to place the patch sequence in the Drafts folder of a specific IMAP server:

$ cat *.patch |git imap-send
Resolving ok
Connecting to []:993... ok
Logging in...
sending 2 messages
100% (2/2) done

At this time, you should be able to go to the Drafts folder
Modify the to field to the mailing list of the patch you want to send
It may need to be copied to the maintainer or the person in charge of that part, and then sent

You can also send patches through an SMTP server
As before, you can set options separately through a series of git config commands
Or manually add them to the sendmail block of the ~ /. gitconfig file:

  smtpencryption = tls
  smtpserver =
  smtpuser =
  smtpserverport = 587

When this is done, you can use git send email to send the patch:

$ git send-email *.patch
Who should the emails appear to be from? [Jasek <>]
Emails will be sent from: Jasek <>
Who should the emails be sent to?
Message-ID to be used as In-Reply-To for the first email? y

Then, for each patch being sent, Git will spit out such a string of log information:

(mbox) Adding cc: Jasek<> from
  \line 'From: Jasek <>'
OK. Log says:
Sendmail: /usr/sbin/sendmail -i
From: Jasek <>
Subject: [PATCH 1/2] added limit to log function
Date: Sat, 30 May 2009 13:29:15 -0700
Message-Id: <>
X-Mailer: git-send-email 1.6.2.rc1.20.g8c5b.dirty
In-Reply-To: <y>
References: <y>

Result: OK

Reference resources: git
The above contents are all composed of deletion, addition and modification according to git official website

Relevant recommendations:

Git notes (22) key points of project contribution
Git notes (21) distributed workflow
Git notes (20) configuration server
Git notes (19) generate SSH public key
Git notes (18) build server Git

Thank you

264 original articles published, 345 praised, 3.2 million visitors+
His message board follow

Tags: git vim github Google

Posted on Sat, 14 Mar 2020 10:08:00 -0400 by Johns3n