Five Git Config Settings Every Dev Needs
Nick Taylor

Nick Taylor @nickytonline

About: GitHub Star and Microsoft MVP. Developer Advocate & Software Engineer who live streams tech content solo & with community friends.

Location:
Montréal, Québec, Canada
Joined:
Mar 11, 2017

Five Git Config Settings Every Dev Needs

Publish Date: Feb 10
48 24

You've probably added some settings to your Git Configuration, but here are some you might not have configured. If you haven't set these up yet, you're doing more manual work than you need to.

Rebase on pull instead of merge

git config --global pull.rebase true
Enter fullscreen mode Exit fullscreen mode

Every time you pull without this, Git creates a merge commit. Do that a few times a day across a team and your git log turns into a mess of "Merge branch 'main' into main" entries that tell you nothing. With rebase, your commits stay on top of the latest changes and your history actually reads like a coherent timeline.

Bonus: I do this a lot, g pull -r origin main (g is my shell alias for git) to keep my branch up to date with main. You can also add

git config --global branch.main.rebase true
Enter fullscreen mode Exit fullscreen mode

and now I just do g pull origin main. Sure it's only two less characters, but one less thing for me to think about.

Auto set upstream on push

git config --global push.autoSetupRemote true
Enter fullscreen mode Exit fullscreen mode

You create a new branch, do your work, push, and Git hits you with this:

fatal: The current branch my-branch has no upstream branch.
To push the current branch and set the remote as upstream, use

    git push --set-upstream origin my-branch

To have this happen automatically for branches without a tracking
upstream, see 'push.autoSetupRemote' in 'git help config'.
Enter fullscreen mode Exit fullscreen mode

Every single time. This setting makes that whole thing go away. Git sets the upstream automatically on your first push to a new branch.

Auto prune on fetch

git config --global fetch.prune true
Enter fullscreen mode Exit fullscreen mode

Stale remote branches pile up silently. Someone merged and deleted their branch weeks ago, but your local still shows it when you run git branch -r. This cleans out those dead references every time you fetch so your branch list reflects what actually exists on the remote.

I had this alias in my shell to prune local and remote branches.

rmmerged() {
  git branch --merged | grep -Ev "(\*|master|main)" | xargs -n 1 git branch -d && git remote prune origin
}
Enter fullscreen mode Exit fullscreen mode

Now, it's simplified to only pruning local branches since the fetch prune setting handles remote ones.

rmmerged() {
  git branch --merged | grep -Ev "(\*|master|main)" | xargs -n 1 git branch -d
}
Enter fullscreen mode Exit fullscreen mode

A better diff algorithm

git config --global diff.algorithm histogram
Enter fullscreen mode Exit fullscreen mode

The default diff algorithm works, but histogram produces cleaner diffs when there are lots of similarly structured lines, think repeated return statements, closing braces, or blank lines. The default algorithm can get confused about which identical lines to match and produces diffs that interleave additions and deletions in ways that are hard to follow. Histogram handles that better. The bigger the file and the more repetitive the structure, the more noticeable the improvement. It's a drop-in upgrade with no downside.

Here's a fictitious example since I had a hard time finding a good example in my own recent commits showing the difference.

Myers Algorithm (Default)

diff --git a/tmp/example_before.js b/tmp/example_after.js
index 30d9ab3c..8ec95ef5 100644
--- a/tmp/example_before.js
+++ b/tmp/example_after.js
@@ -8,15 +8,10 @@ function validateUser(user) {
    if (!user.name) {
      return { error: 'Name is required' };
    }
-  return { valid: true };
-}
-
-function processData(data) {
-  const result = transform(data);
-  if (!result) {
-    return { error: 'Transform failed' };
+  if (!user.id) {
+    return { error: 'ID is required' };
    }
-  return result;
+  return { valid: true };
  }

  function validateProduct(product) {
@@ -26,13 +21,28 @@ function validateProduct(product) {
    if (!product.price) {
      return { error: 'Price is required' };
    }
+  if (!product.name) {
+    return { error: 'Name is required' };
+  }
    return { valid: true };
  }

+function processData(data) {
+  const result = transform(data);
+  if (!result) {
+    return { error: 'Transform failed' };
+  }
+  return result;
+}
+
  function saveToDatabase(item) {
    const connection = getConnection();
    if (!connection) {
      return { error: 'Database connection failed' };
    }
+  const validated = validateItem(item);
+  if (!validated) {
+    return { error: 'Validation failed' };
+  }
    return connection.save(item);
  }
Enter fullscreen mode Exit fullscreen mode

Histogram Algorithm

diff --git a/tmp/example_before.js b/tmp/example_after.js
index 30d9ab3c..8ec95ef5 100644
--- a/tmp/example_before.js
+++ b/tmp/example_after.js
@@ -8,6 +8,22 @@ function validateUser(user) {
    if (!user.name) {
      return { error: 'Name is required' };
    }
+  if (!user.id) {
+    return { error: 'ID is required' };
+  }
+  return { valid: true };
+}
+
+function validateProduct(product) {
+  if (!product) {
+    return { error: 'Product is required' };
+  }
+  if (!product.price) {
+    return { error: 'Price is required' };
+  }
+  if (!product.name) {
+    return { error: 'Name is required' };
+  }
    return { valid: true };
  }

@@ -19,20 +35,14 @@ function processData(data) {
    return result;
  }

-function validateProduct(product) {
-  if (!product) {
-    return { error: 'Product is required' };
-  }
-  if (!product.price) {
-    return { error: 'Price is required' };
-  }
-  return { valid: true };
-}
-
  function saveToDatabase(item) {
    const connection = getConnection();
    if (!connection) {
      return { error: 'Database connection failed' };
    }
+  const validated = validateItem(item);
+  if (!validated) {
+    return { error: 'Validation failed' };
+  }
    return connection.save(item);
  }
Enter fullscreen mode Exit fullscreen mode

Rerere

git config --global rerere.enabled true
Enter fullscreen mode Exit fullscreen mode

Rerere stands for "reuse recorded resolution." When you resolve a merge conflict, Git remembers how you resolved it. The next time the same conflict comes up, Git applies your previous resolution automatically. If you've ever rebased a long-lived branch and had to resolve the same conflict over and over, this is the fix. It won't silently merge things for you in a way you can't review. It records your resolutions and replays them so you don't have to redo the same work.

Want to see what you currently have set? Run git config --global --list and see what's missing.

If you enjoy tips like this, I have a newsletter, OneTipAWeek.com. One developer tip a week. Short & valuable. That's it!

If you want to stay in touch, all my socials are on nickyt.online.

Until the next one!

Photo by Yancy Min on Unsplash

Comments 24 total

  • PASCUAL Gabriel
    PASCUAL GabrielFeb 10, 2026

    Awesome config. I didn't think that I could put the prune on fetch by default. Rebase is my life with git like the "squash on merge" for integrating on main branch. Thanks.

    • Nick Taylor
      Nick TaylorFeb 10, 2026

      Thanks for reading Pascual and glad you found some new additions for your git config!

      Captain America saluting

  • Andy Piper
    Andy PiperFeb 10, 2026

    Always learning new stuff from you, Nick! Nice tips here.

    • Nick Taylor
      Nick TaylorFeb 10, 2026

      Thanks for giving it a read Andy! Hope all is well. 😎

      BB-8 giving a thumbs up

  • Harsh
    Harsh Feb 12, 2026

    Nick, I've been using Git for over a year and somehow never knew about pull.rebase = true until this post. 😅

    Just updated my global config and — wow. Why did no one tell me this sooner? No more random merge commits cluttering my history.

    This is why I still read DEV in 2026. Little productivity gems like this. 🙏

    • Nick Taylor
      Nick TaylorFeb 12, 2026

      Thanks for giving it a read and glad you found it useful! Fun fact. I used to work at DEV!

      Geordi Laforge in a sweater saying “No problem”

  • Ned C
    Ned CFeb 12, 2026

    push.autoSetupRemote is the one that changed my life. I can't believe I spent years typing --set-upstream on every new branch.

    One I'd add: git config --global rerere.enabled true. It remembers how you resolved merge conflicts so if you hit the same conflict again (common during long-lived feature branches), Git just auto-resolves it. Saves a surprising amount of time during rebase-heavy workflows.

    • Nick Taylor
      Nick TaylorFeb 12, 2026

      That one’s in there too at the end! Love rerere!

      • Ned C
        Ned CFeb 12, 2026

        ha, missed that! rerere is one of those features where once you start using it you can't go back. saved me so many times during long-running rebase sessions.

  • Julien Avezou
    Julien AvezouFeb 12, 2026

    I painfully remember fixing the same conflict again and again after a big merge. Rerere could have saved me a lot of pain. Good to know!

  • Shubham Singh
    Shubham SinghFeb 12, 2026

    useful!

  • Vasu Ghanta
    Vasu GhantaFeb 13, 2026

    Great post, @nickytonline! Love these Git gems: pull.rebase, push.autoSetupRemote, fetch.prune, diff.algorithm histogram, and rerere for smoother workflows.

    Pairs perfectly with my take on merge conflicts plaguing 87% of devs—check it readme🚀

  • Shitij Bhatnagar
    Shitij BhatnagarFeb 13, 2026

    Hi, thanks very useful guide here.

    • Nick Taylor
      Nick TaylorFeb 13, 2026

      Glad you found it helpful!

      Hot Rod saying Cool beans!

      • Shitij Bhatnagar
        Shitij BhatnagarFeb 13, 2026

        ya, though my personal preference is not to use use 'git config --global push.autoSetupRemote true' to avoid flooding remote repos with feature branches, but I do believe in frequent & meaningful, compilable commits to branches.

  • Kai Alder
    Kai AlderFeb 13, 2026

    The histogram diff algorithm is one I don't see talked about enough. Switched to it about 6 months ago and the diffs on larger files are noticeably cleaner — especially when you're moving functions around.

    One more I'd throw in: git config --global init.defaultBranch main. Not a productivity thing exactly, but it saves you from that awkward moment when you push a new repo and realize it created a master branch that doesn't match your remote's default.

    • Nick Taylor
      Nick TaylorFeb 13, 2026

      Thanks for giving it a read! Yeah, much cleaner diffs.

      A kangaroo playing an electric guitar

  • Ahmad Firdaus
    Ahmad FirdausFeb 13, 2026

    wow this is very helpful, sometimes i need to take over some of my team git, the push auto upstream and pull reball help me alot thanks

  • 𒎏Wii 🏳️‍⚧️
    𒎏Wii 🏳️‍⚧️Feb 16, 2026

    git config --global pull.rebase true

    Couldn't agree more with this one. Mergig has its place in git, but when pulling commits before pushing everything, 99% of the time I just want to put my work on top of the existing work.

Add comment