threads / patch / 54234

patch, 3 partsFAQ entries for merges and modified files

Subject: [PATCH 0/3] FAQ entries for merges and modified files

## tl;dr

13 messages between Sep 12, 2020 and Sep 20, 2020. Diffs are folded; open one to read it.

replies: 12people: 3as markdown or json

brian m. carlson· Sep 12, 2020, 20:48 UTC · lore
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(+)
brian m. carlson· Sep 12, 2020, 20:48 UTC · re: brian m. carlson · lore

[PATCH 3/3] docs: explain how to deal with files that are always modified

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(+)
Show changes to Documentation/gitfaq.txt +33 −0
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
Martin Ågren· Sep 13, 2020, 15:13 UTC · re: brian m. carlson · lore

Re: [PATCH 3/3] docs: explain how to deal with files that are always modified

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..

Show 7 quoted lines
> 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.
Show 5 quoted lines
> +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
brian m. carlson· Sep 12, 2020, 20:48 UTC · re: brian m. carlson · lore

[PATCH 2/3] docs: explain why reverts are not always applied on merge

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(+)
Show changes to Documentation/gitfaq.txt +19 −0
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
 -----
 
Martin Ågren· Sep 13, 2020, 15:12 UTC · re: brian m. carlson · lore

Re: [PATCH 2/3] docs: explain why reverts are not always applied on merge

On Sat, 12 Sep 2020 at 22:51, brian m. carlson <sandals@crustytoothpaste.net> wrote:

Show 5 quoted lines
>
> 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
brian m. carlson· Sep 12, 2020, 20:48 UTC · re: brian m. carlson · lore

[PATCH 1/3] docs: explain why squash merges are broken with long-running branches

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(+)
Show changes to Documentation/gitfaq.txt +33 −0
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
 -----
 
Martin Ågren· Sep 13, 2020, 15:05 UTC · re: brian m. carlson · lore

Re: [PATCH 1/3] docs: explain why squash merges are broken with long-running branches

On Sat, 12 Sep 2020 at 22:52, brian m. carlson <sandals@crustytoothpaste.net> wrote:

Show 7 quoted lines
>
> 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.
Show 6 quoted lines
> +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
brian m. carlson· Sep 13, 2020, 17:12 UTC · re: Martin Ågren · lore

Re: [PATCH 1/3] docs: explain why squash merges are broken with long-running branches

On 2020-09-13 at 15:05:31, Martin Ågren wrote:
Show 11 quoted lines
> 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.
Show 12 quoted lines
> 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
Junio C Hamano· Sep 12, 2020, 21:48 UTC · re: brian m. carlson · lore

Re: [PATCH 0/3] FAQ entries for merges and modified files

"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.
brian m. carlson· Sep 20, 2020, 23:22 UTC · re: brian m. carlson · lore

[PATCH v2 0/3] FAQ entries for merges and modified files

This series introduces a few new FAQ entries on various topics.
Changes from v1:
* Fix typos in commit messages.
* Talk about case-insensitive file names, not files, to avoid ambiguity.
* Warn people about rebases.
* Switch from "long-running" to "long-lived" and explain the situation
  more clearly without relying on people understanding the meaning of
  the adjective.
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 | 86 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 86 insertions(+)
Diff-intervalle contre v1 :
1:  c4f3e6e19c ! 1:  9f8f348fa8 docs: explain why squash merges are broken with long-running branches
    @@ Commit message
         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
    +    experienced developers may make this mistake, 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.
     
    @@ Documentation/gitfaq.txt: How do I know if I want to do a fetch or a pull?::
     +--------------------
     +
     +[[long-running-squash-merge]]
    -+What kinds of problems can occur when merging long-running branches with squash merges?::
    ++What kinds of problems can occur when merging long-lived 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.
    ++	merges to merge two branches multiple times.  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.
    ++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
    @@ Documentation/gitfaq.txt: How do I know if I want to do a fetch or a pull?::
     +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.
    ++As a consequence, if you want to merge two long-lived branches repeatedly, it's
    ++best to always use a regular merge commit.
     +
      Hooks
      -----
2:  645798d18b ! 2:  248d7e7b4b docs: explain why reverts are not always applied on merge
    @@ Commit message
         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.
    +    merged, 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
    @@ Commit message
     
      ## Documentation/gitfaq.txt ##
     @@ Documentation/gitfaq.txt: 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.
    + As a consequence, if you want to merge two long-lived branches repeatedly, 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?::
    @@ Documentation/gitfaq.txt: original merge base.
     +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.
    ++revert.  Note that rebases rewrite history, so you should avoid rebasing
    ++published branches unless you're sure you're comfortable with that.  See the
    ++NOTES section in linkgit:git-rebase[1] for more details.
     +
      Hooks
      -----
3:  10ad244b1e ! 3:  e2495d4358 docs: explain how to deal with files that are always modified
    @@ Metadata
      ## Commit message ##
         docs: explain how to deal with files that are always modified
     
    -    Users frequently have problems where two files differ only in case,
    +    Users frequently have problems where two filenames 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.
     
    @@ Documentation/gitfaq.txt: information about how to configure files as text or bi
     +	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.
    ++	with multiple files or directories whose names differ only 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
brian m. carlson· Sep 20, 2020, 23:22 UTC · re: brian m. carlson · lore

[PATCH v2 2/3] docs: explain why reverts are not always applied on merge

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 merged, 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 | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)
Show changes to Documentation/gitfaq.txt +21 −0
diff --git a/Documentation/gitfaq.txt b/Documentation/gitfaq.txt
index 51d305d58f..176b097cf7 100644
--- a/Documentation/gitfaq.txt
+++ b/Documentation/gitfaq.txt
@@ -273,6 +273,27 @@ original merge base.
 As a consequence, if you want to merge two long-lived branches repeatedly, 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.  Note that rebases rewrite history, so you should avoid rebasing
+published branches unless you're sure you're comfortable with that.  See the
+NOTES section in linkgit:git-rebase[1] for more details.
+
 Hooks
 -----
 
brian m. carlson· Sep 20, 2020, 23:22 UTC · re: brian m. carlson · lore

[PATCH v2 1/3] docs: explain why squash merges are broken with long-running branches

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 mistake, 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 | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)
Show changes to Documentation/gitfaq.txt +32 −0
diff --git a/Documentation/gitfaq.txt b/Documentation/gitfaq.txt
index 9cd7a592ac..51d305d58f 100644
--- a/Documentation/gitfaq.txt
+++ b/Documentation/gitfaq.txt
@@ -241,6 +241,38 @@ 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-lived branches with squash merges?::
+	In general, there are a variety of problems that can occur when using squash
+	merges to merge two branches multiple times.  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
+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-lived branches repeatedly, it's
+best to always use a regular merge commit.
+
 Hooks
 -----
 
brian m. carlson· Sep 20, 2020, 23:22 UTC · re: brian m. carlson · lore

[PATCH v2 3/3] docs: explain how to deal with files that are always modified

Users frequently have problems where two filenames 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(+)
Show changes to Documentation/gitfaq.txt +33 −0
diff --git a/Documentation/gitfaq.txt b/Documentation/gitfaq.txt
index 176b097cf7..afdaeab850 100644
--- a/Documentation/gitfaq.txt
+++ b/Documentation/gitfaq.txt
@@ -363,6 +363,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 whose names differ only 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

← back to recent threads