git@vger.kernel.org list mirror (unofficial, one of many)
 help / color / mirror / Atom feed
* [PATCH 0/3] FAQ entries for merges and modified files
@ 2020-09-12 20:48 brian m. carlson
  2020-09-12 20:48 ` [PATCH 1/3] docs: explain why squash merges are broken with long-running branches brian m. carlson
                   ` (3 more replies)
  0 siblings, 4 replies; 9+ messages in thread
From: brian m. carlson @ 2020-09-12 20:48 UTC (permalink / raw)
  To: git; +Cc: Martin Ågren

This series introduces a few new FAQ entries on various topics.

The first describes why squash merging doesn't work for long-running
branches.  This is confusing for a lot of folks, including some pretty
advanced developers, so it seems worth documenting.

The second explains why reverts are not applied on merge if the change
has been cherry-picked to both sides.  We have documentation on this
already in git-merge(1), but here we also advise using a rebase instead.
I still see folks confused by this, so hopefully making it a little more
visible (with a little more explanation) will be helpful.

The third departs from the topic of merges to discuss modified files.  I
frequently see folks with perpetually modified files for one of two
reasons: case-sensitivity problems and problems where someone failed to
run the smudge or clean filter.  In fact, we saw one of those problems
recently on the list.  The FAQ entry explains how to handle both
situations and provides suggestions to prevent the former from happening
again.

I've answered all of these questions recently (some multiple times), so
I figured I'd document this so that folks can hopefully discover more of
this themselves and solve their problems more quickly.

brian m. carlson (3):
  docs: explain why squash merges are broken with long-running branches
  docs: explain why reverts are not always applied on merge
  docs: explain how to deal with files that are always modified

 Documentation/gitfaq.txt | 85 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 85 insertions(+)


^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 1/3] docs: explain why squash merges are broken with long-running branches
  2020-09-12 20:48 [PATCH 0/3] FAQ entries for merges and modified files brian m. carlson
@ 2020-09-12 20:48 ` brian m. carlson
  2020-09-13 15:05   ` Martin Ågren
  2020-09-12 20:48 ` [PATCH 2/3] docs: explain why reverts are not always applied on merge brian m. carlson
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 9+ messages in thread
From: brian m. carlson @ 2020-09-12 20:48 UTC (permalink / raw)
  To: git; +Cc: Martin Ågren

In many projects, squash merges are commonly used, primarily to keep a
tidy history in the face of developers who do not use logically
independent, bisectable commits.  As common as this is, this tends to
cause significant problems when squash merges are used to merge
long-running branches due to the lack of any new merge bases.  Even very
experienced developers may make this mistakes, so let's add a FAQ entry
explaining why this is problematic and explaining that regular merge
commits should be used to merge two long-running branches.

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
---
 Documentation/gitfaq.txt | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/Documentation/gitfaq.txt b/Documentation/gitfaq.txt
index 9cd7a592ac..550f4e30d6 100644
--- a/Documentation/gitfaq.txt
+++ b/Documentation/gitfaq.txt
@@ -241,6 +241,39 @@ How do I know if I want to do a fetch or a pull?::
 	ignore the upstream changes.  A pull consists of a fetch followed
 	immediately by either a merge or rebase.  See linkgit:git-pull[1].
 
+Merging and Rebasing
+--------------------
+
+[[long-running-squash-merge]]
+What kinds of problems can occur when merging long-running branches with squash merges?::
+	In general, there are a variety of problems that can occur when using squash
+	merges with long-running branches.  These can include seeing extra commits in
+	`git log` output, with a GUI, or when using the `...` notation to express a
+	range, as well as the possibility of needing to re-resolve conflicts again and
+	again.
++
+When Git does a normal merge between two branches, it considers exactly three
+points: the two branches and a third commit, called the _merge base_, which is
+usually the common ancestor of the commits.  The result of the merge is the sum
+of the changes between the merge base and each head.  When you merge two
+long-running branches with a regular merge commit, this results in a new commit
+which will end up as a merge base when they're merged again, because there is
+now a new common ancestor.  Git doesn't have to consider changes that occurred
+before the merge base, so you don't have to re-resolve any conflicts you
+resolved before.
++
+When you perform a squash merge, a merge commit isn't created; instead, the
+changes from one side are applied as a regular commit to the other side.  This
+means that the merge base for these branches won't have changed, and so when Git
+goes to perform its next merge, it considers all of the changes that it
+considered the last time plus the new changes.  That means any conflicts may
+need to be re-resolved.  Similarly, anything using the `...` notation in `git
+diff`, `git log`, or a GUI will result in showing all of the changes since the
+original merge base.
++
+As a consequence, if you want to merge two long-running branches, it's best to
+always use a regular merge commit.
+
 Hooks
 -----
 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 2/3] docs: explain why reverts are not always applied on merge
  2020-09-12 20:48 [PATCH 0/3] FAQ entries for merges and modified files brian m. carlson
  2020-09-12 20:48 ` [PATCH 1/3] docs: explain why squash merges are broken with long-running branches brian m. carlson
@ 2020-09-12 20:48 ` brian m. carlson
  2020-09-13 15:12   ` Martin Ågren
  2020-09-12 20:48 ` [PATCH 3/3] docs: explain how to deal with files that are always modified brian m. carlson
  2020-09-12 21:48 ` [PATCH 0/3] FAQ entries for merges and modified files Junio C Hamano
  3 siblings, 1 reply; 9+ messages in thread
From: brian m. carlson @ 2020-09-12 20:48 UTC (permalink / raw)
  To: git; +Cc: Martin Ågren

A common scenario is for a user to apply a change to one branch and
cherry-pick it into another, then later revert it in the first branch.
This results in the change being present when the two branches are
merge, which is confusing to many users.

We already have documentation for how this works in `git merge`, but it
is clear from the frequency with which this is asked that it's hard to
grasp.  We also don't explain to users that they are better off doing a
rebase in this case, which will do what they intended.  Let's add an
entry to the FAQ telling users what's happening and advising them to use
rebase here.

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
---
 Documentation/gitfaq.txt | 19 +++++++++++++++++++
 1 file changed, 19 insertions(+)

diff --git a/Documentation/gitfaq.txt b/Documentation/gitfaq.txt
index 550f4e30d6..154f0cce54 100644
--- a/Documentation/gitfaq.txt
+++ b/Documentation/gitfaq.txt
@@ -274,6 +274,25 @@ original merge base.
 As a consequence, if you want to merge two long-running branches, it's best to
 always use a regular merge commit.
 
+[[merge-two-revert-one]]
+If I make a change on two branches but revert it on one, why does the merge of those branches include the change?::
+	By default, when Git does a merge, it uses a strategy called the recursive
+	strategy, which does a fancy three-way merge.  In such a case, when Git
+	performs the merge, it considers exactly three points: the two heads and a
+	third point, called the _merge base_, which is usually the common ancestor of
+	those commits.  Git does not consider the history or the individual commits
+	that have happened on those branches at all.
++
+As a result, if both sides have a change and one side has reverted that change,
+the result is to include the change.  This is because the code has changed on
+one side and there is no net change on the other, and in this scenario, Git
+adopts the change.
++
+If this is a problem for you, you can do a rebase instead, rebasing the branch
+with the revert onto the other branch.  A rebase in this scenario will revert
+the change, because a rebase applies each individual commit, including the
+revert.
+
 Hooks
 -----
 

^ permalink raw reply	[flat|nested] 9+ messages in thread

* [PATCH 3/3] docs: explain how to deal with files that are always modified
  2020-09-12 20:48 [PATCH 0/3] FAQ entries for merges and modified files brian m. carlson
  2020-09-12 20:48 ` [PATCH 1/3] docs: explain why squash merges are broken with long-running branches brian m. carlson
  2020-09-12 20:48 ` [PATCH 2/3] docs: explain why reverts are not always applied on merge brian m. carlson
@ 2020-09-12 20:48 ` brian m. carlson
  2020-09-13 15:13   ` Martin Ågren
  2020-09-12 21:48 ` [PATCH 0/3] FAQ entries for merges and modified files Junio C Hamano
  3 siblings, 1 reply; 9+ messages in thread
From: brian m. carlson @ 2020-09-12 20:48 UTC (permalink / raw)
  To: git; +Cc: Martin Ågren

Users frequently have problems where two files differ only in case,
causing one of those files to show up consistently as being modified.
Let's add a FAQ entry that explains how to deal with that.

In addition, let's explain another common case where files are
consistently modified, which is when files using a smudge or clean
filter have not been run through that filter.  Explain the way to fix
this as well.

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
---
 Documentation/gitfaq.txt | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/Documentation/gitfaq.txt b/Documentation/gitfaq.txt
index 154f0cce54..494ec5dce5 100644
--- a/Documentation/gitfaq.txt
+++ b/Documentation/gitfaq.txt
@@ -362,6 +362,39 @@ information about how to configure files as text or binary.
 You can also control this behavior with the `core.whitespace` setting if you
 don't wish to remove the carriage returns from your line endings.
 
+[[always-modified-files-case]]
+Why do I have a file that's always modified?::
+	Internally, Git always stores file names as sequences of bytes and doesn't
+	perform any encoding or case folding.  However, Windows and macOS by default
+	both perform case folding on file names.  As a result, it's possible to end up
+	with multiple files or directories that differ in case.  Git can handle this
+	just fine, but the file system can store only one of these files, so when Git
+	reads the other file to see its contents, it looks modified.
++
+It's best to remove one of the files such that you only have one file.  You can
+do this with commands like the following (assuming two files `AFile.txt` and
+`afile.txt`) on an otherwise clean working tree:
++
+----
+$ git rm --cached AFile.txt
+$ git commit -m 'Remove files conflicting in case'
+$ git checkout .
+----
++
+This avoids touching the disk, but removes the additional file.  Your project
+may prefer to adopt a naming convention, such as all-lowercase names, to avoid
+this problem from occurring again; such a convention can be checked using a
+`pre-receive` hook or as part of a continuous integration (CI) system.
++
+It is also possible for perpetually modified files to occur on any platform if a
+smudge or clean filter is in use on your system but a file was previously
+committed without running the smudge or clean filter.  To fix this, run the
+following on an otherwise clean working tree:
++
+----
+$ git add --renormalize .
+----
+
 [[recommended-storage-settings]]
 What's the recommended way to store files in Git?::
 	While Git can store and handle any file of any type, there are some

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 0/3] FAQ entries for merges and modified files
  2020-09-12 20:48 [PATCH 0/3] FAQ entries for merges and modified files brian m. carlson
                   ` (2 preceding siblings ...)
  2020-09-12 20:48 ` [PATCH 3/3] docs: explain how to deal with files that are always modified brian m. carlson
@ 2020-09-12 21:48 ` Junio C Hamano
  3 siblings, 0 replies; 9+ messages in thread
From: Junio C Hamano @ 2020-09-12 21:48 UTC (permalink / raw)
  To: brian m. carlson; +Cc: git, Martin Ågren

"brian m. carlson" <sandals@crustytoothpaste.net> writes:

> This series introduces a few new FAQ entries on various topics.

All look like topics worth covering.

Thanks.

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/3] docs: explain why squash merges are broken with long-running branches
  2020-09-12 20:48 ` [PATCH 1/3] docs: explain why squash merges are broken with long-running branches brian m. carlson
@ 2020-09-13 15:05   ` Martin Ågren
  2020-09-13 17:12     ` brian m. carlson
  0 siblings, 1 reply; 9+ messages in thread
From: Martin Ågren @ 2020-09-13 15:05 UTC (permalink / raw)
  To: brian m. carlson; +Cc: Git Mailing List

On Sat, 12 Sep 2020 at 22:52, brian m. carlson
<sandals@crustytoothpaste.net> wrote:
>
> In many projects, squash merges are commonly used, primarily to keep a
> tidy history in the face of developers who do not use logically
> independent, bisectable commits.  As common as this is, this tends to
> cause significant problems when squash merges are used to merge
> long-running branches due to the lack of any new merge bases.  Even very
> experienced developers may make this mistakes, so let's add a FAQ entry

s/mistakes/mistake/

> explaining why this is problematic and explaining that regular merge
> commits should be used to merge two long-running branches.

> +What kinds of problems can occur when merging long-running branches with squash merges?::
> +       In general, there are a variety of problems that can occur when using squash
> +       merges with long-running branches.  These can include seeing extra commits in
> +       `git log` output, with a GUI, or when using the `...` notation to express a
> +       range, as well as the possibility of needing to re-resolve conflicts again and
> +       again.

Very well-written, as always.

I grepped around a little and couldn't find that we're using this "long-
running branch" notion anywhere. I think it might make sense to
define/explain that somewhere early, e.g., with something like "...
merged repeatedly ... more development...".

So in particular, a "long-running" branch is not something like

  I branched off a long time ago, I've been hacking on this feature for
  a long time and the branch has run quite long with lots of commits.
  Now it's time to merge it and be done with it!

Once that piece of background is in place, what you have here reads very
well to me. It was only somewhere halfway through the second paragraph
that I got what you meant by "long-running branch".


Martin

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 2/3] docs: explain why reverts are not always applied on merge
  2020-09-12 20:48 ` [PATCH 2/3] docs: explain why reverts are not always applied on merge brian m. carlson
@ 2020-09-13 15:12   ` Martin Ågren
  0 siblings, 0 replies; 9+ messages in thread
From: Martin Ågren @ 2020-09-13 15:12 UTC (permalink / raw)
  To: brian m. carlson; +Cc: Git Mailing List

On Sat, 12 Sep 2020 at 22:51, brian m. carlson
<sandals@crustytoothpaste.net> wrote:
>
> A common scenario is for a user to apply a change to one branch and
> cherry-pick it into another, then later revert it in the first branch.
> This results in the change being present when the two branches are
> merge, which is confusing to many users.

s/merge/&d/

> +If this is a problem for you, you can do a rebase instead, rebasing the branch
> +with the revert onto the other branch.  A rebase in this scenario will revert
> +the change, because a rebase applies each individual commit, including the
> +revert.

Should this include the usual disclaimer about only rebasing a branch if
it hasn't been published or if you (and your team) is willing and able
to handle the fallout? I dunno. This piece of text is vague enough that
the reader will have to pick up the "rebase ... onto" keywords and
figure out the details some other way (and to be clear: I think that's a
good thing). I think that should be sufficient and they'll find the
disclaimer when they look up "rebase", if they don't already know it.


Martin

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 3/3] docs: explain how to deal with files that are always modified
  2020-09-12 20:48 ` [PATCH 3/3] docs: explain how to deal with files that are always modified brian m. carlson
@ 2020-09-13 15:13   ` Martin Ågren
  0 siblings, 0 replies; 9+ messages in thread
From: Martin Ågren @ 2020-09-13 15:13 UTC (permalink / raw)
  To: brian m. carlson; +Cc: Git Mailing List

On Sat, 12 Sep 2020 at 22:52, brian m. carlson
<sandals@crustytoothpaste.net> wrote:
>
> Users frequently have problems where two files differ only in case,

s/files/filenames/ ? Anyway, clear enough here, but let's keep it in
mind when reading the proposed FAQ entry..

> causing one of those files to show up consistently as being modified.
> Let's add a FAQ entry that explains how to deal with that.
>
> In addition, let's explain another common case where files are
> consistently modified, which is when files using a smudge or clean
> filter have not been run through that filter.  Explain the way to fix
> this as well.

> +Why do I have a file that's always modified?::
> +       Internally, Git always stores file names as sequences of bytes and doesn't
> +       perform any encoding or case folding.  However, Windows and macOS by default
> +       both perform case folding on file names.  As a result, it's possible to end up
> +       with multiple files or directories that differ in case.  Git can handle this

I think this could be clearer with something like s/that differ in case/where
their names only differ in case/, i.e., explicitly talking about the names
of the files and also sticking an "only" in there.

> +       just fine, but the file system can store only one of these files, so when Git
> +       reads the other file to see its contents, it looks modified.

That concludes my reading of these patches. I only had some minor
comments. I think these are good entries to add to the FAQ.


Martin

^ permalink raw reply	[flat|nested] 9+ messages in thread

* Re: [PATCH 1/3] docs: explain why squash merges are broken with long-running branches
  2020-09-13 15:05   ` Martin Ågren
@ 2020-09-13 17:12     ` brian m. carlson
  0 siblings, 0 replies; 9+ messages in thread
From: brian m. carlson @ 2020-09-13 17:12 UTC (permalink / raw)
  To: Martin Ågren; +Cc: Git Mailing List

[-- Attachment #1: Type: text/plain, Size: 2075 bytes --]

On 2020-09-13 at 15:05:31, Martin Ågren wrote:
> On Sat, 12 Sep 2020 at 22:52, brian m. carlson
> <sandals@crustytoothpaste.net> wrote:
> >
> > In many projects, squash merges are commonly used, primarily to keep a
> > tidy history in the face of developers who do not use logically
> > independent, bisectable commits.  As common as this is, this tends to
> > cause significant problems when squash merges are used to merge
> > long-running branches due to the lack of any new merge bases.  Even very
> > experienced developers may make this mistakes, so let's add a FAQ entry
> 
> s/mistakes/mistake/

Will fix.

> Very well-written, as always.
> 
> I grepped around a little and couldn't find that we're using this "long-
> running branch" notion anywhere. I think it might make sense to
> define/explain that somewhere early, e.g., with something like "...
> merged repeatedly ... more development...".
> 
> So in particular, a "long-running" branch is not something like
> 
>   I branched off a long time ago, I've been hacking on this feature for
>   a long time and the branch has run quite long with lots of commits.
>   Now it's time to merge it and be done with it!

Correct.  By "long-running branch", I mean a branch into which code
routinely gets integrated from feature branches.  For example, the
branches master and develop in a Git Flow workflow, or per-version
release branches if you use that workflow.  I didn't mean an otherwise
divergent branch which has persisted for a long time.

The problem happens, essentially, if you have two branches and you merge
one of them into another repeatedly with squash merges, so I'll be sure
to make that clear.  That will probably help with intelligibility for
non-native speakers as well.

> Once that piece of background is in place, what you have here reads very
> well to me. It was only somewhere halfway through the second paragraph
> that I got what you meant by "long-running branch".

Thanks, this is helpful feedback.
-- 
brian m. carlson: Houston, Texas, US

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 263 bytes --]

^ permalink raw reply	[flat|nested] 9+ messages in thread

end of thread, other threads:[~2020-09-13 17:12 UTC | newest]

Thread overview: 9+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-09-12 20:48 [PATCH 0/3] FAQ entries for merges and modified files brian m. carlson
2020-09-12 20:48 ` [PATCH 1/3] docs: explain why squash merges are broken with long-running branches brian m. carlson
2020-09-13 15:05   ` Martin Ågren
2020-09-13 17:12     ` brian m. carlson
2020-09-12 20:48 ` [PATCH 2/3] docs: explain why reverts are not always applied on merge brian m. carlson
2020-09-13 15:12   ` Martin Ågren
2020-09-12 20:48 ` [PATCH 3/3] docs: explain how to deal with files that are always modified brian m. carlson
2020-09-13 15:13   ` Martin Ågren
2020-09-12 21:48 ` [PATCH 0/3] FAQ entries for merges and modified files Junio C Hamano

git@vger.kernel.org list mirror (unofficial, one of many)

This inbox may be cloned and mirrored by anyone:

	git clone --mirror https://public-inbox.org/git
	git clone --mirror http://ou63pmih66umazou.onion/git
	git clone --mirror http://czquwvybam4bgbro.onion/git
	git clone --mirror http://hjrcffqmbrq6wope.onion/git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V1 git git/ https://public-inbox.org/git \
		git@vger.kernel.org
	public-inbox-index git

Example config snippet for mirrors.
Newsgroups are available over NNTP:
	nntp://news.public-inbox.org/inbox.comp.version-control.git
	nntp://ou63pmih66umazou.onion/inbox.comp.version-control.git
	nntp://czquwvybam4bgbro.onion/inbox.comp.version-control.git
	nntp://hjrcffqmbrq6wope.onion/inbox.comp.version-control.git
	nntp://news.gmane.io/gmane.comp.version-control.git
 note: .onion URLs require Tor: https://www.torproject.org/

code repositories for the project(s) associated with this inbox:

	https://80x24.org/mirrors/git.git

AGPL code for this site: git clone https://public-inbox.org/public-inbox.git